@contractspec/module.ai-chat 4.1.5 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -3
- package/dist/browser/core/index.js +53 -17
- package/dist/browser/index.js +982 -426
- package/dist/browser/presentation/components/index.js +975 -419
- package/dist/browser/presentation/hooks/index.js +8 -1
- package/dist/browser/presentation/index.js +983 -427
- package/dist/core/create-chat-route.d.ts +14 -3
- package/dist/core/index.js +53 -17
- package/dist/core/message-types.d.ts +4 -0
- package/dist/index.js +982 -426
- package/dist/node/core/index.js +53 -17
- package/dist/node/index.js +982 -426
- package/dist/node/presentation/components/index.js +975 -419
- package/dist/node/presentation/hooks/index.js +8 -1
- package/dist/node/presentation/index.js +983 -427
- package/dist/presentation/components/ChainOfThought.d.ts +30 -0
- package/dist/presentation/components/ChatInput.d.ts +3 -4
- package/dist/presentation/components/ChatMessage.d.ts +6 -4
- package/dist/presentation/components/ChatWithExport.d.ts +14 -1
- package/dist/presentation/components/ChatWithSidebar.d.ts +12 -1
- package/dist/presentation/components/Reasoning.d.ts +24 -0
- package/dist/presentation/components/Sources.d.ts +22 -0
- package/dist/presentation/components/Suggestion.d.ts +12 -0
- package/dist/presentation/components/ToolResultRenderer.d.ts +20 -3
- package/dist/presentation/components/component-types.d.ts +52 -0
- package/dist/presentation/components/index.d.ts +6 -1
- package/dist/presentation/components/index.js +975 -419
- package/dist/presentation/hooks/index.js +8 -1
- package/dist/presentation/index.js +983 -427
- package/package.json +15 -15
|
@@ -80,8 +80,8 @@ function ChatContainer({
|
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
// src/presentation/components/ChatMessage.tsx
|
|
83
|
-
import * as
|
|
84
|
-
import { cn as
|
|
83
|
+
import * as React4 from "react";
|
|
84
|
+
import { cn as cn5 } from "@contractspec/lib.ui-kit-web/ui/utils";
|
|
85
85
|
import { Avatar, AvatarFallback } from "@contractspec/lib.ui-kit-web/ui/avatar";
|
|
86
86
|
import { Skeleton } from "@contractspec/lib.ui-kit-web/ui/skeleton";
|
|
87
87
|
import {
|
|
@@ -90,7 +90,6 @@ import {
|
|
|
90
90
|
AlertCircle,
|
|
91
91
|
Copy as Copy2,
|
|
92
92
|
Check as Check2,
|
|
93
|
-
ExternalLink,
|
|
94
93
|
Wrench,
|
|
95
94
|
Pencil,
|
|
96
95
|
X
|
|
@@ -244,22 +243,98 @@ function CodePreview({
|
|
|
244
243
|
// src/presentation/components/ToolResultRenderer.tsx
|
|
245
244
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
246
245
|
"use client";
|
|
246
|
+
function isUIMessageLike(result) {
|
|
247
|
+
return typeof result === "object" && result !== null && "parts" in result && Array.isArray(result.parts);
|
|
248
|
+
}
|
|
247
249
|
function isPresentationToolResult(result) {
|
|
248
250
|
return typeof result === "object" && result !== null && "presentationKey" in result && typeof result.presentationKey === "string";
|
|
249
251
|
}
|
|
250
252
|
function isFormToolResult(result) {
|
|
251
253
|
return typeof result === "object" && result !== null && "formKey" in result && typeof result.formKey === "string";
|
|
252
254
|
}
|
|
255
|
+
function isDataViewToolResult(result) {
|
|
256
|
+
return typeof result === "object" && result !== null && "dataViewKey" in result && typeof result.dataViewKey === "string";
|
|
257
|
+
}
|
|
258
|
+
function UIMessagePartRenderer({
|
|
259
|
+
part,
|
|
260
|
+
presentationRenderer,
|
|
261
|
+
formRenderer,
|
|
262
|
+
dataViewRenderer,
|
|
263
|
+
depth = 0
|
|
264
|
+
}) {
|
|
265
|
+
if (part === null || part === undefined)
|
|
266
|
+
return null;
|
|
267
|
+
const p = part;
|
|
268
|
+
if (p.type === "text" && typeof p.text === "string") {
|
|
269
|
+
return /* @__PURE__ */ jsx3("p", {
|
|
270
|
+
className: "text-sm whitespace-pre-wrap",
|
|
271
|
+
children: p.text
|
|
272
|
+
}, depth);
|
|
273
|
+
}
|
|
274
|
+
if (p.type && String(p.type).startsWith("tool-") && p.output) {
|
|
275
|
+
const output = p.output;
|
|
276
|
+
if (isUIMessageLike(output)) {
|
|
277
|
+
return /* @__PURE__ */ jsx3("div", {
|
|
278
|
+
className: "border-border ml-2 border-l-2 pl-2",
|
|
279
|
+
children: /* @__PURE__ */ jsx3(UIMessagePartsRenderer, {
|
|
280
|
+
parts: output.parts ?? [],
|
|
281
|
+
presentationRenderer,
|
|
282
|
+
formRenderer,
|
|
283
|
+
dataViewRenderer,
|
|
284
|
+
depth: depth + 1
|
|
285
|
+
})
|
|
286
|
+
}, depth);
|
|
287
|
+
}
|
|
288
|
+
return /* @__PURE__ */ jsx3("pre", {
|
|
289
|
+
className: "bg-background overflow-x-auto rounded p-2 text-xs",
|
|
290
|
+
children: typeof output === "object" ? JSON.stringify(output, null, 2) : String(output)
|
|
291
|
+
}, depth);
|
|
292
|
+
}
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
function UIMessagePartsRenderer({
|
|
296
|
+
parts,
|
|
297
|
+
presentationRenderer,
|
|
298
|
+
formRenderer,
|
|
299
|
+
dataViewRenderer,
|
|
300
|
+
depth = 0
|
|
301
|
+
}) {
|
|
302
|
+
if (parts.length === 0)
|
|
303
|
+
return null;
|
|
304
|
+
return /* @__PURE__ */ jsx3("div", {
|
|
305
|
+
className: "space-y-2",
|
|
306
|
+
children: parts.map((part, i) => /* @__PURE__ */ jsx3(UIMessagePartRenderer, {
|
|
307
|
+
part,
|
|
308
|
+
presentationRenderer,
|
|
309
|
+
formRenderer,
|
|
310
|
+
dataViewRenderer,
|
|
311
|
+
depth
|
|
312
|
+
}, `${depth}-${i}`))
|
|
313
|
+
});
|
|
314
|
+
}
|
|
253
315
|
function ToolResultRenderer({
|
|
254
|
-
toolName,
|
|
316
|
+
toolName: _toolName,
|
|
255
317
|
result,
|
|
256
318
|
presentationRenderer,
|
|
257
319
|
formRenderer,
|
|
258
|
-
|
|
320
|
+
dataViewRenderer,
|
|
321
|
+
showRawFallback = true,
|
|
322
|
+
renderNestedUIMessage = true
|
|
259
323
|
}) {
|
|
260
324
|
if (result === undefined || result === null) {
|
|
261
325
|
return null;
|
|
262
326
|
}
|
|
327
|
+
if (renderNestedUIMessage && isUIMessageLike(result) && (result.parts?.length ?? 0) > 0) {
|
|
328
|
+
return /* @__PURE__ */ jsx3("div", {
|
|
329
|
+
className: "border-border bg-background/50 mt-2 rounded-md border p-3",
|
|
330
|
+
children: /* @__PURE__ */ jsx3(UIMessagePartsRenderer, {
|
|
331
|
+
parts: result.parts ?? [],
|
|
332
|
+
presentationRenderer,
|
|
333
|
+
formRenderer,
|
|
334
|
+
dataViewRenderer
|
|
335
|
+
})
|
|
336
|
+
});
|
|
337
|
+
}
|
|
263
338
|
if (isPresentationToolResult(result) && presentationRenderer) {
|
|
264
339
|
const rendered = presentationRenderer(result.presentationKey, result.data);
|
|
265
340
|
if (rendered != null) {
|
|
@@ -278,6 +353,15 @@ function ToolResultRenderer({
|
|
|
278
353
|
});
|
|
279
354
|
}
|
|
280
355
|
}
|
|
356
|
+
if (isDataViewToolResult(result) && dataViewRenderer) {
|
|
357
|
+
const rendered = dataViewRenderer(result.dataViewKey, result.items);
|
|
358
|
+
if (rendered != null) {
|
|
359
|
+
return /* @__PURE__ */ jsx3("div", {
|
|
360
|
+
className: "border-border bg-background/50 mt-2 rounded-md border p-3",
|
|
361
|
+
children: rendered
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
281
365
|
if (!showRawFallback) {
|
|
282
366
|
return null;
|
|
283
367
|
}
|
|
@@ -295,8 +379,158 @@ function ToolResultRenderer({
|
|
|
295
379
|
});
|
|
296
380
|
}
|
|
297
381
|
|
|
382
|
+
// src/presentation/components/Reasoning.tsx
|
|
383
|
+
import * as React3 from "react";
|
|
384
|
+
import {
|
|
385
|
+
Collapsible,
|
|
386
|
+
CollapsibleContent,
|
|
387
|
+
CollapsibleTrigger
|
|
388
|
+
} from "@contractspec/lib.ui-kit-web/ui/collapsible";
|
|
389
|
+
import { cn as cn3 } from "@contractspec/lib.ui-kit-web/ui/utils";
|
|
390
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
391
|
+
"use client";
|
|
392
|
+
function Reasoning({
|
|
393
|
+
isStreaming = false,
|
|
394
|
+
open,
|
|
395
|
+
defaultOpen = false,
|
|
396
|
+
onOpenChange,
|
|
397
|
+
children,
|
|
398
|
+
className
|
|
399
|
+
}) {
|
|
400
|
+
const [internalOpen, setInternalOpen] = React3.useState(defaultOpen);
|
|
401
|
+
const prevStreamingRef = React3.useRef(isStreaming);
|
|
402
|
+
const isControlled = open !== undefined;
|
|
403
|
+
React3.useEffect(() => {
|
|
404
|
+
if (isStreaming) {
|
|
405
|
+
if (isControlled) {
|
|
406
|
+
onOpenChange?.(true);
|
|
407
|
+
} else {
|
|
408
|
+
setInternalOpen(true);
|
|
409
|
+
}
|
|
410
|
+
} else if (prevStreamingRef.current) {
|
|
411
|
+
if (isControlled) {
|
|
412
|
+
onOpenChange?.(false);
|
|
413
|
+
} else {
|
|
414
|
+
setInternalOpen(false);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
prevStreamingRef.current = isStreaming;
|
|
418
|
+
}, [isStreaming, isControlled, onOpenChange]);
|
|
419
|
+
const handleOpenChange = React3.useCallback((next) => {
|
|
420
|
+
if (isControlled) {
|
|
421
|
+
onOpenChange?.(next);
|
|
422
|
+
} else {
|
|
423
|
+
setInternalOpen(next);
|
|
424
|
+
}
|
|
425
|
+
}, [isControlled, onOpenChange]);
|
|
426
|
+
return /* @__PURE__ */ jsx4(Collapsible, {
|
|
427
|
+
open: isControlled ? open : internalOpen,
|
|
428
|
+
onOpenChange: handleOpenChange,
|
|
429
|
+
className: cn3("w-full", className),
|
|
430
|
+
children
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
function ReasoningTrigger({
|
|
434
|
+
children,
|
|
435
|
+
isStreaming = false,
|
|
436
|
+
className
|
|
437
|
+
}) {
|
|
438
|
+
return /* @__PURE__ */ jsxs4(CollapsibleTrigger, {
|
|
439
|
+
className: cn3("text-muted-foreground hover:bg-muted hover:text-foreground flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors", className),
|
|
440
|
+
children: [
|
|
441
|
+
isStreaming && /* @__PURE__ */ jsx4("span", {
|
|
442
|
+
className: "bg-primary h-1.5 w-1.5 animate-pulse rounded-full",
|
|
443
|
+
"aria-hidden": true
|
|
444
|
+
}),
|
|
445
|
+
children ?? (isStreaming ? "Thinking..." : "View reasoning")
|
|
446
|
+
]
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
function ReasoningContent({
|
|
450
|
+
children,
|
|
451
|
+
className
|
|
452
|
+
}) {
|
|
453
|
+
return /* @__PURE__ */ jsx4(CollapsibleContent, {
|
|
454
|
+
children: /* @__PURE__ */ jsx4("div", {
|
|
455
|
+
className: cn3("text-muted-foreground bg-muted mt-1 rounded-md p-2 text-sm", className),
|
|
456
|
+
children: /* @__PURE__ */ jsx4("p", {
|
|
457
|
+
className: "whitespace-pre-wrap",
|
|
458
|
+
children
|
|
459
|
+
})
|
|
460
|
+
})
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// src/presentation/components/Sources.tsx
|
|
465
|
+
import {
|
|
466
|
+
Collapsible as Collapsible2,
|
|
467
|
+
CollapsibleContent as CollapsibleContent2,
|
|
468
|
+
CollapsibleTrigger as CollapsibleTrigger2
|
|
469
|
+
} from "@contractspec/lib.ui-kit-web/ui/collapsible";
|
|
470
|
+
import { cn as cn4 } from "@contractspec/lib.ui-kit-web/ui/utils";
|
|
471
|
+
import { ExternalLink } from "lucide-react";
|
|
472
|
+
import { jsx as jsx5, jsxs as jsxs5, Fragment } from "react/jsx-runtime";
|
|
473
|
+
"use client";
|
|
474
|
+
function Sources({ children, className }) {
|
|
475
|
+
return /* @__PURE__ */ jsx5(Collapsible2, {
|
|
476
|
+
className: cn4("mt-2", className),
|
|
477
|
+
defaultOpen: false,
|
|
478
|
+
children
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
function SourcesTrigger({
|
|
482
|
+
count,
|
|
483
|
+
children,
|
|
484
|
+
className
|
|
485
|
+
}) {
|
|
486
|
+
return /* @__PURE__ */ jsx5(CollapsibleTrigger2, {
|
|
487
|
+
className: cn4("text-muted-foreground hover:text-foreground hover:bg-muted inline-flex cursor-pointer items-center gap-1.5 rounded-md px-2 py-1 text-xs transition-colors", className),
|
|
488
|
+
children: children ?? /* @__PURE__ */ jsxs5(Fragment, {
|
|
489
|
+
children: [
|
|
490
|
+
/* @__PURE__ */ jsx5(ExternalLink, {
|
|
491
|
+
className: "h-3 w-3"
|
|
492
|
+
}),
|
|
493
|
+
count,
|
|
494
|
+
" source",
|
|
495
|
+
count !== 1 ? "s" : ""
|
|
496
|
+
]
|
|
497
|
+
})
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
function SourcesContent({ children, className }) {
|
|
501
|
+
return /* @__PURE__ */ jsx5(CollapsibleContent2, {
|
|
502
|
+
children: /* @__PURE__ */ jsx5("div", {
|
|
503
|
+
className: cn4("mt-2 flex flex-wrap gap-2", className),
|
|
504
|
+
children
|
|
505
|
+
})
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
function Source({
|
|
509
|
+
href,
|
|
510
|
+
title,
|
|
511
|
+
className,
|
|
512
|
+
children,
|
|
513
|
+
...props
|
|
514
|
+
}) {
|
|
515
|
+
return /* @__PURE__ */ jsx5("a", {
|
|
516
|
+
href,
|
|
517
|
+
target: "_blank",
|
|
518
|
+
rel: "noopener noreferrer",
|
|
519
|
+
className: cn4("text-muted-foreground hover:text-foreground bg-muted inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs transition-colors", className),
|
|
520
|
+
...props,
|
|
521
|
+
children: children ?? /* @__PURE__ */ jsxs5(Fragment, {
|
|
522
|
+
children: [
|
|
523
|
+
/* @__PURE__ */ jsx5(ExternalLink, {
|
|
524
|
+
className: "h-3 w-3"
|
|
525
|
+
}),
|
|
526
|
+
title ?? href
|
|
527
|
+
]
|
|
528
|
+
})
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
|
|
298
532
|
// src/presentation/components/ChatMessage.tsx
|
|
299
|
-
import { jsx as
|
|
533
|
+
import { jsx as jsx6, jsxs as jsxs6, Fragment as Fragment2 } from "react/jsx-runtime";
|
|
300
534
|
"use client";
|
|
301
535
|
function extractCodeBlocks(content) {
|
|
302
536
|
const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/g;
|
|
@@ -319,11 +553,11 @@ function renderInlineMarkdown(text) {
|
|
|
319
553
|
let key = 0;
|
|
320
554
|
while ((match = linkRegex.exec(text)) !== null) {
|
|
321
555
|
if (match.index > lastIndex) {
|
|
322
|
-
parts.push(/* @__PURE__ */
|
|
556
|
+
parts.push(/* @__PURE__ */ jsx6("span", {
|
|
323
557
|
children: text.slice(lastIndex, match.index)
|
|
324
558
|
}, key++));
|
|
325
559
|
}
|
|
326
|
-
parts.push(/* @__PURE__ */
|
|
560
|
+
parts.push(/* @__PURE__ */ jsx6("a", {
|
|
327
561
|
href: match[2],
|
|
328
562
|
target: "_blank",
|
|
329
563
|
rel: "noopener noreferrer",
|
|
@@ -333,7 +567,7 @@ function renderInlineMarkdown(text) {
|
|
|
333
567
|
lastIndex = match.index + match[0].length;
|
|
334
568
|
}
|
|
335
569
|
if (lastIndex < text.length) {
|
|
336
|
-
parts.push(/* @__PURE__ */
|
|
570
|
+
parts.push(/* @__PURE__ */ jsx6("span", {
|
|
337
571
|
children: text.slice(lastIndex)
|
|
338
572
|
}, key++));
|
|
339
573
|
}
|
|
@@ -342,7 +576,7 @@ function renderInlineMarkdown(text) {
|
|
|
342
576
|
function MessageContent({ content }) {
|
|
343
577
|
const codeBlocks = extractCodeBlocks(content);
|
|
344
578
|
if (codeBlocks.length === 0) {
|
|
345
|
-
return /* @__PURE__ */
|
|
579
|
+
return /* @__PURE__ */ jsx6("p", {
|
|
346
580
|
className: "whitespace-pre-wrap",
|
|
347
581
|
children: renderInlineMarkdown(content)
|
|
348
582
|
});
|
|
@@ -353,12 +587,12 @@ function MessageContent({ content }) {
|
|
|
353
587
|
for (const block of codeBlocks) {
|
|
354
588
|
const [before, after] = remaining.split(block.raw);
|
|
355
589
|
if (before) {
|
|
356
|
-
parts.push(/* @__PURE__ */
|
|
590
|
+
parts.push(/* @__PURE__ */ jsx6("p", {
|
|
357
591
|
className: "whitespace-pre-wrap",
|
|
358
592
|
children: renderInlineMarkdown(before.trim())
|
|
359
593
|
}, key++));
|
|
360
594
|
}
|
|
361
|
-
parts.push(/* @__PURE__ */
|
|
595
|
+
parts.push(/* @__PURE__ */ jsx6(CodePreview, {
|
|
362
596
|
code: block.code,
|
|
363
597
|
language: block.language,
|
|
364
598
|
className: "my-2"
|
|
@@ -366,15 +600,22 @@ function MessageContent({ content }) {
|
|
|
366
600
|
remaining = after ?? "";
|
|
367
601
|
}
|
|
368
602
|
if (remaining.trim()) {
|
|
369
|
-
parts.push(/* @__PURE__ */
|
|
603
|
+
parts.push(/* @__PURE__ */ jsx6("p", {
|
|
370
604
|
className: "whitespace-pre-wrap",
|
|
371
605
|
children: renderInlineMarkdown(remaining.trim())
|
|
372
606
|
}, key++));
|
|
373
607
|
}
|
|
374
|
-
return /* @__PURE__ */
|
|
608
|
+
return /* @__PURE__ */ jsx6(Fragment2, {
|
|
375
609
|
children: parts
|
|
376
610
|
});
|
|
377
611
|
}
|
|
612
|
+
function toolStatusToCotStatus(status) {
|
|
613
|
+
if (status === "completed")
|
|
614
|
+
return "complete";
|
|
615
|
+
if (status === "running")
|
|
616
|
+
return "active";
|
|
617
|
+
return "pending";
|
|
618
|
+
}
|
|
378
619
|
function ChatMessage({
|
|
379
620
|
message,
|
|
380
621
|
className,
|
|
@@ -386,119 +627,128 @@ function ChatMessage({
|
|
|
386
627
|
editable = false,
|
|
387
628
|
onEdit,
|
|
388
629
|
presentationRenderer,
|
|
389
|
-
formRenderer
|
|
630
|
+
formRenderer,
|
|
631
|
+
dataViewRenderer,
|
|
632
|
+
components: comps
|
|
390
633
|
}) {
|
|
391
|
-
const [copied, setCopied] =
|
|
634
|
+
const [copied, setCopied] = React4.useState(false);
|
|
392
635
|
const isUser = message.role === "user";
|
|
393
636
|
const isError = message.status === "error";
|
|
394
637
|
const isStreaming = message.status === "streaming";
|
|
395
|
-
const handleCopy =
|
|
638
|
+
const handleCopy = React4.useCallback(async () => {
|
|
396
639
|
await navigator.clipboard.writeText(message.content);
|
|
397
640
|
setCopied(true);
|
|
398
641
|
setTimeout(() => setCopied(false), 2000);
|
|
399
642
|
}, [message.content]);
|
|
400
|
-
const handleSelectChange =
|
|
643
|
+
const handleSelectChange = React4.useCallback((checked) => {
|
|
401
644
|
if (checked !== "indeterminate")
|
|
402
645
|
onSelect?.(message.id);
|
|
403
646
|
}, [message.id, onSelect]);
|
|
404
|
-
const [isEditing, setIsEditing] =
|
|
405
|
-
const [editContent, setEditContent] =
|
|
406
|
-
|
|
647
|
+
const [isEditing, setIsEditing] = React4.useState(false);
|
|
648
|
+
const [editContent, setEditContent] = React4.useState(message.content);
|
|
649
|
+
const editTextareaRef = React4.useRef(null);
|
|
650
|
+
React4.useEffect(() => {
|
|
407
651
|
setEditContent(message.content);
|
|
408
652
|
}, [message.content]);
|
|
409
|
-
|
|
653
|
+
React4.useEffect(() => {
|
|
654
|
+
if (isEditing) {
|
|
655
|
+
editTextareaRef.current?.focus();
|
|
656
|
+
}
|
|
657
|
+
}, [isEditing]);
|
|
658
|
+
const handleStartEdit = React4.useCallback(() => {
|
|
410
659
|
setEditContent(message.content);
|
|
411
660
|
setIsEditing(true);
|
|
412
661
|
}, [message.content]);
|
|
413
|
-
const handleSaveEdit =
|
|
662
|
+
const handleSaveEdit = React4.useCallback(async () => {
|
|
414
663
|
const trimmed = editContent.trim();
|
|
415
664
|
if (trimmed !== message.content) {
|
|
416
665
|
await onEdit?.(message.id, trimmed);
|
|
417
666
|
}
|
|
418
667
|
setIsEditing(false);
|
|
419
668
|
}, [editContent, message.id, message.content, onEdit]);
|
|
420
|
-
const handleCancelEdit =
|
|
669
|
+
const handleCancelEdit = React4.useCallback(() => {
|
|
421
670
|
setEditContent(message.content);
|
|
422
671
|
setIsEditing(false);
|
|
423
672
|
}, [message.content]);
|
|
424
|
-
return /* @__PURE__ */
|
|
425
|
-
className:
|
|
673
|
+
return /* @__PURE__ */ jsxs6("div", {
|
|
674
|
+
className: cn5("group flex gap-3", isUser && "flex-row-reverse", className),
|
|
426
675
|
children: [
|
|
427
|
-
selectable && /* @__PURE__ */
|
|
428
|
-
className:
|
|
429
|
-
children: /* @__PURE__ */
|
|
676
|
+
selectable && /* @__PURE__ */ jsx6("div", {
|
|
677
|
+
className: cn5("flex shrink-0 items-start pt-1", "opacity-0 transition-opacity group-hover:opacity-100"),
|
|
678
|
+
children: /* @__PURE__ */ jsx6(Checkbox, {
|
|
430
679
|
checked: selected,
|
|
431
680
|
onCheckedChange: handleSelectChange,
|
|
432
681
|
"aria-label": selected ? "Deselect message" : "Select message"
|
|
433
682
|
})
|
|
434
683
|
}),
|
|
435
|
-
showAvatar && /* @__PURE__ */
|
|
684
|
+
showAvatar && /* @__PURE__ */ jsx6(Avatar, {
|
|
436
685
|
className: "h-8 w-8 shrink-0",
|
|
437
|
-
children: /* @__PURE__ */
|
|
438
|
-
className:
|
|
439
|
-
children: isUser ? /* @__PURE__ */
|
|
686
|
+
children: /* @__PURE__ */ jsx6(AvatarFallback, {
|
|
687
|
+
className: cn5(isUser ? "bg-primary text-primary-foreground" : "bg-muted"),
|
|
688
|
+
children: isUser ? /* @__PURE__ */ jsx6(User, {
|
|
440
689
|
className: "h-4 w-4"
|
|
441
|
-
}) : /* @__PURE__ */
|
|
690
|
+
}) : /* @__PURE__ */ jsx6(Bot, {
|
|
442
691
|
className: "h-4 w-4"
|
|
443
692
|
})
|
|
444
693
|
})
|
|
445
694
|
}),
|
|
446
|
-
/* @__PURE__ */
|
|
447
|
-
className:
|
|
695
|
+
/* @__PURE__ */ jsxs6("div", {
|
|
696
|
+
className: cn5("flex max-w-[80%] flex-col gap-1", isUser && "items-end"),
|
|
448
697
|
children: [
|
|
449
|
-
/* @__PURE__ */
|
|
450
|
-
className:
|
|
451
|
-
children: isError && message.error ? /* @__PURE__ */
|
|
698
|
+
/* @__PURE__ */ jsx6("div", {
|
|
699
|
+
className: cn5("rounded-2xl px-4 py-2", isUser ? "bg-primary text-primary-foreground" : "bg-muted text-foreground", isError && "border-destructive bg-destructive/10 border"),
|
|
700
|
+
children: isError && message.error ? /* @__PURE__ */ jsxs6("div", {
|
|
452
701
|
className: "flex items-start gap-2",
|
|
453
702
|
children: [
|
|
454
|
-
/* @__PURE__ */
|
|
703
|
+
/* @__PURE__ */ jsx6(AlertCircle, {
|
|
455
704
|
className: "text-destructive mt-0.5 h-4 w-4 shrink-0"
|
|
456
705
|
}),
|
|
457
|
-
/* @__PURE__ */
|
|
706
|
+
/* @__PURE__ */ jsxs6("div", {
|
|
458
707
|
children: [
|
|
459
|
-
/* @__PURE__ */
|
|
708
|
+
/* @__PURE__ */ jsx6("p", {
|
|
460
709
|
className: "text-destructive font-medium",
|
|
461
710
|
children: message.error.code
|
|
462
711
|
}),
|
|
463
|
-
/* @__PURE__ */
|
|
712
|
+
/* @__PURE__ */ jsx6("p", {
|
|
464
713
|
className: "text-muted-foreground text-sm",
|
|
465
714
|
children: message.error.message
|
|
466
715
|
})
|
|
467
716
|
]
|
|
468
717
|
})
|
|
469
718
|
]
|
|
470
|
-
}) : isEditing ? /* @__PURE__ */
|
|
719
|
+
}) : isEditing ? /* @__PURE__ */ jsxs6("div", {
|
|
471
720
|
className: "flex flex-col gap-2",
|
|
472
721
|
children: [
|
|
473
|
-
/* @__PURE__ */
|
|
722
|
+
/* @__PURE__ */ jsx6("textarea", {
|
|
723
|
+
ref: editTextareaRef,
|
|
474
724
|
value: editContent,
|
|
475
725
|
onChange: (e) => setEditContent(e.target.value),
|
|
476
726
|
className: "bg-background/50 min-h-[80px] w-full resize-y rounded-md border px-3 py-2 text-sm",
|
|
477
727
|
rows: 4,
|
|
478
|
-
|
|
728
|
+
"aria-label": "Edit message"
|
|
479
729
|
}),
|
|
480
|
-
/* @__PURE__ */
|
|
730
|
+
/* @__PURE__ */ jsxs6("div", {
|
|
481
731
|
className: "flex gap-2",
|
|
482
732
|
children: [
|
|
483
|
-
/* @__PURE__ */
|
|
733
|
+
/* @__PURE__ */ jsxs6(Button2, {
|
|
484
734
|
variant: "default",
|
|
485
735
|
size: "sm",
|
|
486
736
|
onPress: handleSaveEdit,
|
|
487
737
|
"aria-label": "Save edit",
|
|
488
738
|
children: [
|
|
489
|
-
/* @__PURE__ */
|
|
739
|
+
/* @__PURE__ */ jsx6(Check2, {
|
|
490
740
|
className: "h-3 w-3"
|
|
491
741
|
}),
|
|
492
742
|
"Save"
|
|
493
743
|
]
|
|
494
744
|
}),
|
|
495
|
-
/* @__PURE__ */
|
|
745
|
+
/* @__PURE__ */ jsxs6(Button2, {
|
|
496
746
|
variant: "ghost",
|
|
497
747
|
size: "sm",
|
|
498
748
|
onPress: handleCancelEdit,
|
|
499
749
|
"aria-label": "Cancel edit",
|
|
500
750
|
children: [
|
|
501
|
-
/* @__PURE__ */
|
|
751
|
+
/* @__PURE__ */ jsx6(X, {
|
|
502
752
|
className: "h-3 w-3"
|
|
503
753
|
}),
|
|
504
754
|
"Cancel"
|
|
@@ -507,153 +757,256 @@ function ChatMessage({
|
|
|
507
757
|
]
|
|
508
758
|
})
|
|
509
759
|
]
|
|
510
|
-
}) : isStreaming && !message.content ? /* @__PURE__ */
|
|
760
|
+
}) : isStreaming && !message.content ? /* @__PURE__ */ jsxs6("div", {
|
|
511
761
|
className: "flex flex-col gap-2",
|
|
512
762
|
children: [
|
|
513
|
-
/* @__PURE__ */
|
|
763
|
+
/* @__PURE__ */ jsx6(Skeleton, {
|
|
514
764
|
className: "h-4 w-48"
|
|
515
765
|
}),
|
|
516
|
-
/* @__PURE__ */
|
|
766
|
+
/* @__PURE__ */ jsx6(Skeleton, {
|
|
517
767
|
className: "h-4 w-32"
|
|
518
768
|
})
|
|
519
769
|
]
|
|
520
|
-
}) : /* @__PURE__ */
|
|
770
|
+
}) : /* @__PURE__ */ jsx6(MessageContent, {
|
|
521
771
|
content: message.content
|
|
522
772
|
})
|
|
523
773
|
}),
|
|
524
|
-
/* @__PURE__ */
|
|
525
|
-
className:
|
|
774
|
+
/* @__PURE__ */ jsxs6("div", {
|
|
775
|
+
className: cn5("flex items-center gap-2 text-xs", "text-muted-foreground opacity-0 transition-opacity", "group-hover:opacity-100"),
|
|
526
776
|
children: [
|
|
527
|
-
/* @__PURE__ */
|
|
777
|
+
/* @__PURE__ */ jsx6("span", {
|
|
528
778
|
children: new Date(message.createdAt).toLocaleTimeString([], {
|
|
529
779
|
hour: "2-digit",
|
|
530
780
|
minute: "2-digit"
|
|
531
781
|
})
|
|
532
782
|
}),
|
|
533
|
-
message.usage && /* @__PURE__ */
|
|
783
|
+
message.usage && /* @__PURE__ */ jsxs6("span", {
|
|
534
784
|
children: [
|
|
535
785
|
message.usage.inputTokens + message.usage.outputTokens,
|
|
536
786
|
" tokens"
|
|
537
787
|
]
|
|
538
788
|
}),
|
|
539
|
-
showCopy && !isUser && message.content && /* @__PURE__ */
|
|
789
|
+
showCopy && !isUser && message.content && /* @__PURE__ */ jsx6(Button2, {
|
|
540
790
|
variant: "ghost",
|
|
541
791
|
size: "sm",
|
|
542
792
|
className: "h-6 w-6 p-0",
|
|
543
793
|
onPress: handleCopy,
|
|
544
794
|
"aria-label": copied ? "Copied" : "Copy message",
|
|
545
|
-
children: copied ? /* @__PURE__ */
|
|
795
|
+
children: copied ? /* @__PURE__ */ jsx6(Check2, {
|
|
546
796
|
className: "h-3 w-3"
|
|
547
|
-
}) : /* @__PURE__ */
|
|
797
|
+
}) : /* @__PURE__ */ jsx6(Copy2, {
|
|
548
798
|
className: "h-3 w-3"
|
|
549
799
|
})
|
|
550
800
|
}),
|
|
551
|
-
editable && isUser && !isEditing && /* @__PURE__ */
|
|
801
|
+
editable && isUser && !isEditing && /* @__PURE__ */ jsx6(Button2, {
|
|
552
802
|
variant: "ghost",
|
|
553
803
|
size: "sm",
|
|
554
804
|
className: "h-6 w-6 p-0",
|
|
555
805
|
onPress: handleStartEdit,
|
|
556
806
|
"aria-label": "Edit message",
|
|
557
|
-
children: /* @__PURE__ */
|
|
807
|
+
children: /* @__PURE__ */ jsx6(Pencil, {
|
|
558
808
|
className: "h-3 w-3"
|
|
559
809
|
})
|
|
560
810
|
})
|
|
561
811
|
]
|
|
562
812
|
}),
|
|
563
|
-
message.reasoning && /* @__PURE__ */
|
|
564
|
-
|
|
813
|
+
message.reasoning && (comps?.Reasoning ? /* @__PURE__ */ jsx6(comps.Reasoning, {
|
|
814
|
+
isStreaming: isStreaming && !!message.reasoning,
|
|
815
|
+
children: message.reasoning
|
|
816
|
+
}) : /* @__PURE__ */ jsxs6(Reasoning, {
|
|
817
|
+
isStreaming: isStreaming && !!message.reasoning,
|
|
818
|
+
className: "mt-2",
|
|
565
819
|
children: [
|
|
566
|
-
/* @__PURE__ */
|
|
567
|
-
|
|
568
|
-
children: "View reasoning"
|
|
820
|
+
/* @__PURE__ */ jsx6(ReasoningTrigger, {
|
|
821
|
+
isStreaming
|
|
569
822
|
}),
|
|
570
|
-
/* @__PURE__ */
|
|
571
|
-
|
|
572
|
-
children: /* @__PURE__ */ jsx4("p", {
|
|
573
|
-
className: "whitespace-pre-wrap",
|
|
574
|
-
children: message.reasoning
|
|
575
|
-
})
|
|
823
|
+
/* @__PURE__ */ jsx6(ReasoningContent, {
|
|
824
|
+
children: message.reasoning
|
|
576
825
|
})
|
|
577
826
|
]
|
|
578
|
-
}),
|
|
579
|
-
message.sources && message.sources.length > 0 &&
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
827
|
+
})),
|
|
828
|
+
message.sources && message.sources.length > 0 && (() => {
|
|
829
|
+
const SourcesComp = comps?.Sources;
|
|
830
|
+
const SourcesTriggerComp = comps?.SourcesTrigger;
|
|
831
|
+
const SourceComp = comps?.Source;
|
|
832
|
+
if (SourcesComp && SourcesTriggerComp && SourceComp) {
|
|
833
|
+
return /* @__PURE__ */ jsxs6(SourcesComp, {
|
|
834
|
+
children: [
|
|
835
|
+
/* @__PURE__ */ jsx6(SourcesTriggerComp, {
|
|
836
|
+
count: message.sources.length
|
|
837
|
+
}),
|
|
838
|
+
message.sources.map((source) => /* @__PURE__ */ jsx6(SourceComp, {
|
|
839
|
+
href: source.url ?? "#",
|
|
840
|
+
title: source.title || source.url || source.id
|
|
841
|
+
}, source.id))
|
|
842
|
+
]
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
return /* @__PURE__ */ jsxs6(Sources, {
|
|
846
|
+
className: "mt-2",
|
|
586
847
|
children: [
|
|
587
|
-
/* @__PURE__ */
|
|
588
|
-
|
|
848
|
+
/* @__PURE__ */ jsx6(SourcesTrigger, {
|
|
849
|
+
count: message.sources.length
|
|
589
850
|
}),
|
|
590
|
-
|
|
851
|
+
/* @__PURE__ */ jsx6(SourcesContent, {
|
|
852
|
+
children: message.sources.map((source) => /* @__PURE__ */ jsx6(Source, {
|
|
853
|
+
href: source.url ?? "#",
|
|
854
|
+
title: source.title || source.url || source.id
|
|
855
|
+
}, source.id))
|
|
856
|
+
})
|
|
591
857
|
]
|
|
592
|
-
}
|
|
593
|
-
}),
|
|
594
|
-
message.toolCalls && message.toolCalls.length > 0 &&
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
tc.name,
|
|
606
|
-
/* @__PURE__ */ jsx4("span", {
|
|
607
|
-
className: cn3("ml-auto rounded px-1.5 py-0.5 text-xs", tc.status === "completed" && "bg-green-500/20 text-green-700 dark:text-green-400", tc.status === "error" && "bg-destructive/20 text-destructive", tc.status === "running" && "bg-blue-500/20 text-blue-700 dark:text-blue-400"),
|
|
608
|
-
children: tc.status
|
|
609
|
-
})
|
|
610
|
-
]
|
|
611
|
-
}),
|
|
612
|
-
/* @__PURE__ */ jsxs4("div", {
|
|
613
|
-
className: "border-border border-t px-3 py-2 text-xs",
|
|
858
|
+
});
|
|
859
|
+
})(),
|
|
860
|
+
message.toolCalls && message.toolCalls.length > 0 && (() => {
|
|
861
|
+
const CotComp = comps?.ChainOfThought;
|
|
862
|
+
const CotStepComp = comps?.ChainOfThoughtStep;
|
|
863
|
+
if (CotComp && CotStepComp) {
|
|
864
|
+
return /* @__PURE__ */ jsx6(CotComp, {
|
|
865
|
+
defaultOpen: false,
|
|
866
|
+
className: "mt-2",
|
|
867
|
+
children: message.toolCalls.map((tc) => /* @__PURE__ */ jsxs6(CotStepComp, {
|
|
868
|
+
label: tc.name,
|
|
869
|
+
description: Object.keys(tc.args).length > 0 ? `Input: ${JSON.stringify(tc.args)}` : undefined,
|
|
870
|
+
status: toolStatusToCotStatus(tc.status),
|
|
614
871
|
children: [
|
|
615
|
-
|
|
616
|
-
className: "
|
|
617
|
-
children:
|
|
618
|
-
/* @__PURE__ */ jsx4("span", {
|
|
619
|
-
className: "text-muted-foreground font-medium",
|
|
620
|
-
children: "Input:"
|
|
621
|
-
}),
|
|
622
|
-
/* @__PURE__ */ jsx4("pre", {
|
|
623
|
-
className: "bg-background mt-1 overflow-x-auto rounded p-2",
|
|
624
|
-
children: JSON.stringify(tc.args, null, 2)
|
|
625
|
-
})
|
|
626
|
-
]
|
|
872
|
+
tc.preliminary && tc.status === "running" && /* @__PURE__ */ jsx6("p", {
|
|
873
|
+
className: "text-muted-foreground mt-1 text-xs",
|
|
874
|
+
children: "Running…"
|
|
627
875
|
}),
|
|
628
|
-
tc.result !== undefined && /* @__PURE__ */
|
|
876
|
+
(tc.result !== undefined || tc.nestedParts?.length) && /* @__PURE__ */ jsx6(ToolResultRenderer, {
|
|
629
877
|
toolName: tc.name,
|
|
630
|
-
result: tc.result,
|
|
878
|
+
result: tc.nestedParts?.length ? { parts: tc.nestedParts } : tc.result,
|
|
631
879
|
presentationRenderer,
|
|
632
880
|
formRenderer,
|
|
881
|
+
dataViewRenderer,
|
|
633
882
|
showRawFallback: true
|
|
634
883
|
}),
|
|
635
|
-
tc.error && /* @__PURE__ */
|
|
636
|
-
className: "text-destructive mt-1",
|
|
884
|
+
tc.error && /* @__PURE__ */ jsx6("p", {
|
|
885
|
+
className: "text-destructive mt-1 text-xs",
|
|
637
886
|
children: tc.error
|
|
638
887
|
})
|
|
639
888
|
]
|
|
640
|
-
})
|
|
641
|
-
|
|
642
|
-
}
|
|
643
|
-
|
|
889
|
+
}, tc.id))
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
return /* @__PURE__ */ jsx6("div", {
|
|
893
|
+
className: "mt-2 space-y-2",
|
|
894
|
+
children: message.toolCalls.map((tc) => /* @__PURE__ */ jsxs6("details", {
|
|
895
|
+
className: "bg-muted border-border rounded-md border",
|
|
896
|
+
children: [
|
|
897
|
+
/* @__PURE__ */ jsxs6("summary", {
|
|
898
|
+
className: "flex cursor-pointer items-center gap-2 px-3 py-2 text-sm font-medium",
|
|
899
|
+
children: [
|
|
900
|
+
/* @__PURE__ */ jsx6(Wrench, {
|
|
901
|
+
className: "text-muted-foreground h-4 w-4"
|
|
902
|
+
}),
|
|
903
|
+
tc.name,
|
|
904
|
+
/* @__PURE__ */ jsx6("span", {
|
|
905
|
+
className: cn5("ml-auto rounded px-1.5 py-0.5 text-xs", tc.status === "completed" && "bg-green-500/20 text-green-700 dark:text-green-400", tc.status === "error" && "bg-destructive/20 text-destructive", tc.status === "running" && "bg-blue-500/20 text-blue-700 dark:text-blue-400"),
|
|
906
|
+
children: tc.status
|
|
907
|
+
})
|
|
908
|
+
]
|
|
909
|
+
}),
|
|
910
|
+
/* @__PURE__ */ jsxs6("div", {
|
|
911
|
+
className: "border-border border-t px-3 py-2 text-xs",
|
|
912
|
+
children: [
|
|
913
|
+
Object.keys(tc.args).length > 0 && /* @__PURE__ */ jsxs6("div", {
|
|
914
|
+
className: "mb-2",
|
|
915
|
+
children: [
|
|
916
|
+
/* @__PURE__ */ jsx6("span", {
|
|
917
|
+
className: "text-muted-foreground font-medium",
|
|
918
|
+
children: "Input:"
|
|
919
|
+
}),
|
|
920
|
+
/* @__PURE__ */ jsx6("pre", {
|
|
921
|
+
className: "bg-background mt-1 overflow-x-auto rounded p-2",
|
|
922
|
+
children: JSON.stringify(tc.args, null, 2)
|
|
923
|
+
})
|
|
924
|
+
]
|
|
925
|
+
}),
|
|
926
|
+
tc.preliminary && tc.status === "running" && /* @__PURE__ */ jsx6("p", {
|
|
927
|
+
className: "text-muted-foreground mt-1 text-xs",
|
|
928
|
+
children: "Running…"
|
|
929
|
+
}),
|
|
930
|
+
(tc.result !== undefined || tc.nestedParts?.length) && /* @__PURE__ */ jsx6(ToolResultRenderer, {
|
|
931
|
+
toolName: tc.name,
|
|
932
|
+
result: tc.nestedParts?.length ? { parts: tc.nestedParts } : tc.result,
|
|
933
|
+
presentationRenderer,
|
|
934
|
+
formRenderer,
|
|
935
|
+
dataViewRenderer,
|
|
936
|
+
showRawFallback: true
|
|
937
|
+
}),
|
|
938
|
+
tc.error && /* @__PURE__ */ jsx6("p", {
|
|
939
|
+
className: "text-destructive mt-1",
|
|
940
|
+
children: tc.error
|
|
941
|
+
})
|
|
942
|
+
]
|
|
943
|
+
})
|
|
944
|
+
]
|
|
945
|
+
}, tc.id))
|
|
946
|
+
});
|
|
947
|
+
})()
|
|
644
948
|
]
|
|
645
949
|
})
|
|
646
950
|
]
|
|
647
951
|
});
|
|
648
952
|
}
|
|
649
953
|
// src/presentation/components/ChatInput.tsx
|
|
650
|
-
import * as
|
|
651
|
-
import { cn as
|
|
954
|
+
import * as React5 from "react";
|
|
955
|
+
import { cn as cn6 } from "@contractspec/lib.ui-kit-web/ui/utils";
|
|
652
956
|
import { Textarea } from "@contractspec/lib.design-system";
|
|
653
957
|
import { Button as Button3 } from "@contractspec/lib.design-system";
|
|
654
|
-
import {
|
|
655
|
-
|
|
958
|
+
import {
|
|
959
|
+
Send,
|
|
960
|
+
Paperclip,
|
|
961
|
+
X as X2,
|
|
962
|
+
Loader2,
|
|
963
|
+
FileText,
|
|
964
|
+
Code,
|
|
965
|
+
ImageIcon
|
|
966
|
+
} from "lucide-react";
|
|
967
|
+
import { jsx as jsx7, jsxs as jsxs7, Fragment as Fragment3 } from "react/jsx-runtime";
|
|
656
968
|
"use client";
|
|
969
|
+
var DEFAULT_MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
|
|
970
|
+
var CODE_EXTENSIONS = [
|
|
971
|
+
"ts",
|
|
972
|
+
"tsx",
|
|
973
|
+
"js",
|
|
974
|
+
"jsx",
|
|
975
|
+
"py",
|
|
976
|
+
"go",
|
|
977
|
+
"rs",
|
|
978
|
+
"java",
|
|
979
|
+
"json",
|
|
980
|
+
"md",
|
|
981
|
+
"txt",
|
|
982
|
+
"yaml",
|
|
983
|
+
"yml"
|
|
984
|
+
];
|
|
985
|
+
function readFileAsContent(file) {
|
|
986
|
+
const extension = file.name.split(".").pop()?.toLowerCase() ?? "";
|
|
987
|
+
const isCode = CODE_EXTENSIONS.includes(extension);
|
|
988
|
+
const isImage = file.type.startsWith("image/");
|
|
989
|
+
if (isImage) {
|
|
990
|
+
return new Promise((resolve, reject) => {
|
|
991
|
+
const reader = new FileReader;
|
|
992
|
+
reader.onload = () => {
|
|
993
|
+
const result = reader.result;
|
|
994
|
+
resolve({
|
|
995
|
+
content: typeof result === "string" ? result : new TextDecoder().decode(result ?? new ArrayBuffer(0)),
|
|
996
|
+
type: "image"
|
|
997
|
+
});
|
|
998
|
+
};
|
|
999
|
+
reader.onerror = () => reject(new Error("Could not read file"));
|
|
1000
|
+
reader.readAsDataURL(file);
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
return file.text().then((content) => ({
|
|
1004
|
+
content,
|
|
1005
|
+
type: isCode ? "code" : "file"
|
|
1006
|
+
})).catch(() => {
|
|
1007
|
+
throw new Error("Could not read file");
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
657
1010
|
function ChatInput({
|
|
658
1011
|
onSend,
|
|
659
1012
|
disabled = false,
|
|
@@ -661,147 +1014,163 @@ function ChatInput({
|
|
|
661
1014
|
placeholder = "Type a message...",
|
|
662
1015
|
className,
|
|
663
1016
|
showAttachments = true,
|
|
664
|
-
maxAttachments = 5
|
|
1017
|
+
maxAttachments = 5,
|
|
1018
|
+
maxFileSizeBytes = DEFAULT_MAX_FILE_SIZE_BYTES
|
|
665
1019
|
}) {
|
|
666
|
-
const [content, setContent] =
|
|
667
|
-
const [attachments, setAttachments] =
|
|
668
|
-
const
|
|
669
|
-
const
|
|
1020
|
+
const [content, setContent] = React5.useState("");
|
|
1021
|
+
const [attachments, setAttachments] = React5.useState([]);
|
|
1022
|
+
const [fileError, setFileError] = React5.useState(null);
|
|
1023
|
+
const textareaRef = React5.useRef(null);
|
|
1024
|
+
const fileInputRef = React5.useRef(null);
|
|
670
1025
|
const canSend = content.trim().length > 0 || attachments.length > 0;
|
|
671
|
-
const handleSubmit =
|
|
1026
|
+
const handleSubmit = React5.useCallback((e) => {
|
|
672
1027
|
e?.preventDefault();
|
|
673
1028
|
if (!canSend || disabled || isLoading)
|
|
674
1029
|
return;
|
|
675
1030
|
onSend(content.trim(), attachments.length > 0 ? attachments : undefined);
|
|
676
1031
|
setContent("");
|
|
677
1032
|
setAttachments([]);
|
|
1033
|
+
setFileError(null);
|
|
678
1034
|
textareaRef.current?.focus();
|
|
679
1035
|
}, [canSend, content, attachments, disabled, isLoading, onSend]);
|
|
680
|
-
const handleKeyDown =
|
|
1036
|
+
const handleKeyDown = React5.useCallback((e) => {
|
|
681
1037
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
682
1038
|
e.preventDefault();
|
|
683
1039
|
handleSubmit();
|
|
684
1040
|
}
|
|
685
1041
|
}, [handleSubmit]);
|
|
686
|
-
const handleFileSelect =
|
|
1042
|
+
const handleFileSelect = React5.useCallback(async (e) => {
|
|
687
1043
|
const files = e.target.files;
|
|
688
1044
|
if (!files)
|
|
689
1045
|
return;
|
|
1046
|
+
setFileError(null);
|
|
690
1047
|
const newAttachments = [];
|
|
1048
|
+
const errors = [];
|
|
691
1049
|
for (const file of Array.from(files)) {
|
|
692
|
-
if (attachments.length + newAttachments.length >= maxAttachments)
|
|
1050
|
+
if (attachments.length + newAttachments.length >= maxAttachments) {
|
|
1051
|
+
errors.push(`Maximum ${maxAttachments} attachments allowed`);
|
|
693
1052
|
break;
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
1053
|
+
}
|
|
1054
|
+
if (file.size > maxFileSizeBytes) {
|
|
1055
|
+
errors.push(`${file.name} exceeds ${Math.round(maxFileSizeBytes / 1024 / 1024)}MB limit`);
|
|
1056
|
+
continue;
|
|
1057
|
+
}
|
|
1058
|
+
try {
|
|
1059
|
+
const { content: fileContent, type } = await readFileAsContent(file);
|
|
1060
|
+
newAttachments.push({
|
|
1061
|
+
id: `att_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`,
|
|
1062
|
+
type,
|
|
1063
|
+
name: file.name,
|
|
1064
|
+
content: fileContent,
|
|
1065
|
+
mimeType: file.type,
|
|
1066
|
+
size: file.size
|
|
1067
|
+
});
|
|
1068
|
+
} catch {
|
|
1069
|
+
errors.push(`Could not read ${file.name}`);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
if (errors.length > 0) {
|
|
1073
|
+
setFileError(errors[0] ?? "Could not add file");
|
|
1074
|
+
}
|
|
1075
|
+
if (newAttachments.length > 0) {
|
|
1076
|
+
setAttachments((prev) => [...prev, ...newAttachments]);
|
|
714
1077
|
}
|
|
715
|
-
setAttachments((prev) => [...prev, ...newAttachments]);
|
|
716
1078
|
e.target.value = "";
|
|
717
|
-
}, [attachments.length, maxAttachments]);
|
|
718
|
-
const removeAttachment =
|
|
1079
|
+
}, [attachments.length, maxAttachments, maxFileSizeBytes]);
|
|
1080
|
+
const removeAttachment = React5.useCallback((id) => {
|
|
719
1081
|
setAttachments((prev) => prev.filter((a) => a.id !== id));
|
|
720
1082
|
}, []);
|
|
721
|
-
return /* @__PURE__ */
|
|
722
|
-
className:
|
|
1083
|
+
return /* @__PURE__ */ jsxs7("div", {
|
|
1084
|
+
className: cn6("flex flex-col gap-2", className),
|
|
723
1085
|
children: [
|
|
724
|
-
attachments.length > 0 && /* @__PURE__ */
|
|
1086
|
+
attachments.length > 0 && /* @__PURE__ */ jsx7("div", {
|
|
725
1087
|
className: "flex flex-wrap gap-2",
|
|
726
|
-
children: attachments.map((attachment) => /* @__PURE__ */
|
|
727
|
-
className:
|
|
1088
|
+
children: attachments.map((attachment) => /* @__PURE__ */ jsxs7("div", {
|
|
1089
|
+
className: cn6("flex items-center gap-1.5 rounded-md px-2 py-1", "bg-muted text-muted-foreground text-sm"),
|
|
728
1090
|
children: [
|
|
729
|
-
attachment.type === "code" ? /* @__PURE__ */
|
|
1091
|
+
attachment.type === "code" ? /* @__PURE__ */ jsx7(Code, {
|
|
1092
|
+
className: "h-3.5 w-3.5"
|
|
1093
|
+
}) : attachment.type === "image" ? /* @__PURE__ */ jsx7(ImageIcon, {
|
|
730
1094
|
className: "h-3.5 w-3.5"
|
|
731
|
-
}) : /* @__PURE__ */
|
|
1095
|
+
}) : /* @__PURE__ */ jsx7(FileText, {
|
|
732
1096
|
className: "h-3.5 w-3.5"
|
|
733
1097
|
}),
|
|
734
|
-
/* @__PURE__ */
|
|
1098
|
+
/* @__PURE__ */ jsx7("span", {
|
|
735
1099
|
className: "max-w-[150px] truncate",
|
|
736
1100
|
children: attachment.name
|
|
737
1101
|
}),
|
|
738
|
-
/* @__PURE__ */
|
|
1102
|
+
/* @__PURE__ */ jsx7("button", {
|
|
739
1103
|
type: "button",
|
|
740
1104
|
onClick: () => removeAttachment(attachment.id),
|
|
741
1105
|
className: "hover:text-foreground",
|
|
742
1106
|
"aria-label": `Remove ${attachment.name}`,
|
|
743
|
-
children: /* @__PURE__ */
|
|
1107
|
+
children: /* @__PURE__ */ jsx7(X2, {
|
|
744
1108
|
className: "h-3.5 w-3.5"
|
|
745
1109
|
})
|
|
746
1110
|
})
|
|
747
1111
|
]
|
|
748
1112
|
}, attachment.id))
|
|
749
1113
|
}),
|
|
750
|
-
/* @__PURE__ */
|
|
1114
|
+
fileError && /* @__PURE__ */ jsx7("p", {
|
|
1115
|
+
className: "text-destructive text-xs",
|
|
1116
|
+
role: "alert",
|
|
1117
|
+
children: fileError
|
|
1118
|
+
}),
|
|
1119
|
+
/* @__PURE__ */ jsxs7("form", {
|
|
751
1120
|
onSubmit: handleSubmit,
|
|
752
1121
|
className: "flex items-end gap-2",
|
|
753
1122
|
children: [
|
|
754
|
-
showAttachments && /* @__PURE__ */
|
|
1123
|
+
showAttachments && /* @__PURE__ */ jsxs7(Fragment3, {
|
|
755
1124
|
children: [
|
|
756
|
-
/* @__PURE__ */
|
|
1125
|
+
/* @__PURE__ */ jsx7("input", {
|
|
757
1126
|
ref: fileInputRef,
|
|
758
1127
|
type: "file",
|
|
759
1128
|
multiple: true,
|
|
760
|
-
accept: ".ts,.tsx,.js,.jsx,.json,.md,.txt,.py,.go,.rs,.java,.yaml,.yml",
|
|
1129
|
+
accept: ".ts,.tsx,.js,.jsx,.json,.md,.txt,.py,.go,.rs,.java,.yaml,.yml,image/*",
|
|
761
1130
|
onChange: handleFileSelect,
|
|
762
1131
|
className: "hidden",
|
|
763
1132
|
"aria-label": "Attach files"
|
|
764
1133
|
}),
|
|
765
|
-
/* @__PURE__ */
|
|
1134
|
+
/* @__PURE__ */ jsx7(Button3, {
|
|
766
1135
|
type: "button",
|
|
767
1136
|
variant: "ghost",
|
|
768
1137
|
size: "sm",
|
|
769
1138
|
onPress: () => fileInputRef.current?.click(),
|
|
770
1139
|
disabled: disabled || attachments.length >= maxAttachments,
|
|
771
1140
|
"aria-label": "Attach files",
|
|
772
|
-
children: /* @__PURE__ */
|
|
1141
|
+
children: /* @__PURE__ */ jsx7(Paperclip, {
|
|
773
1142
|
className: "h-4 w-4"
|
|
774
1143
|
})
|
|
775
1144
|
})
|
|
776
1145
|
]
|
|
777
1146
|
}),
|
|
778
|
-
/* @__PURE__ */
|
|
1147
|
+
/* @__PURE__ */ jsx7("div", {
|
|
779
1148
|
className: "relative flex-1",
|
|
780
|
-
children: /* @__PURE__ */
|
|
1149
|
+
children: /* @__PURE__ */ jsx7(Textarea, {
|
|
781
1150
|
value: content,
|
|
782
1151
|
onChange: (e) => setContent(e.target.value),
|
|
783
1152
|
onKeyDown: handleKeyDown,
|
|
784
1153
|
placeholder,
|
|
785
1154
|
disabled,
|
|
786
|
-
className:
|
|
1155
|
+
className: cn6("max-h-[200px] min-h-[44px] resize-none pr-12", "focus-visible:ring-1"),
|
|
787
1156
|
rows: 1,
|
|
788
1157
|
"aria-label": "Chat message"
|
|
789
1158
|
})
|
|
790
1159
|
}),
|
|
791
|
-
/* @__PURE__ */
|
|
1160
|
+
/* @__PURE__ */ jsx7(Button3, {
|
|
792
1161
|
type: "submit",
|
|
793
1162
|
disabled: !canSend || disabled || isLoading,
|
|
794
1163
|
size: "sm",
|
|
795
1164
|
"aria-label": isLoading ? "Sending..." : "Send message",
|
|
796
|
-
children: isLoading ? /* @__PURE__ */
|
|
1165
|
+
children: isLoading ? /* @__PURE__ */ jsx7(Loader2, {
|
|
797
1166
|
className: "h-4 w-4 animate-spin"
|
|
798
|
-
}) : /* @__PURE__ */
|
|
1167
|
+
}) : /* @__PURE__ */ jsx7(Send, {
|
|
799
1168
|
className: "h-4 w-4"
|
|
800
1169
|
})
|
|
801
1170
|
})
|
|
802
1171
|
]
|
|
803
1172
|
}),
|
|
804
|
-
/* @__PURE__ */
|
|
1173
|
+
/* @__PURE__ */ jsx7("p", {
|
|
805
1174
|
className: "text-muted-foreground text-xs",
|
|
806
1175
|
children: "Press Enter to send, Shift+Enter for new line"
|
|
807
1176
|
})
|
|
@@ -809,7 +1178,7 @@ function ChatInput({
|
|
|
809
1178
|
});
|
|
810
1179
|
}
|
|
811
1180
|
// src/presentation/components/ChatExportToolbar.tsx
|
|
812
|
-
import * as
|
|
1181
|
+
import * as React6 from "react";
|
|
813
1182
|
import { Download as Download2, FileText as FileText2, Copy as Copy3, Check as Check3, Plus, GitFork } from "lucide-react";
|
|
814
1183
|
import { Button as Button4 } from "@contractspec/lib.design-system";
|
|
815
1184
|
import {
|
|
@@ -1021,7 +1390,7 @@ function exportToFile(messages, format, conversation) {
|
|
|
1021
1390
|
}
|
|
1022
1391
|
|
|
1023
1392
|
// src/presentation/components/ChatExportToolbar.tsx
|
|
1024
|
-
import { jsx as
|
|
1393
|
+
import { jsx as jsx8, jsxs as jsxs8, Fragment as Fragment4 } from "react/jsx-runtime";
|
|
1025
1394
|
"use client";
|
|
1026
1395
|
function ChatExportToolbar({
|
|
1027
1396
|
messages,
|
|
@@ -1036,19 +1405,19 @@ function ChatExportToolbar({
|
|
|
1036
1405
|
onCreateNew,
|
|
1037
1406
|
onFork
|
|
1038
1407
|
}) {
|
|
1039
|
-
const [copied, setCopied] =
|
|
1040
|
-
const toExport =
|
|
1408
|
+
const [copied, setCopied] = React6.useState(false);
|
|
1409
|
+
const toExport = React6.useMemo(() => {
|
|
1041
1410
|
if (selectedIds.size > 0) {
|
|
1042
1411
|
const idSet = selectedIds;
|
|
1043
1412
|
return messages.filter((m) => idSet.has(m.id));
|
|
1044
1413
|
}
|
|
1045
1414
|
return messages;
|
|
1046
1415
|
}, [messages, selectedIds]);
|
|
1047
|
-
const handleExport =
|
|
1416
|
+
const handleExport = React6.useCallback((format) => {
|
|
1048
1417
|
exportToFile(toExport, format, conversation);
|
|
1049
1418
|
onExported?.(format, toExport.length);
|
|
1050
1419
|
}, [toExport, conversation, onExported]);
|
|
1051
|
-
const handleCopy =
|
|
1420
|
+
const handleCopy = React6.useCallback(async () => {
|
|
1052
1421
|
const content = formatMessagesAsMarkdown(toExport);
|
|
1053
1422
|
await navigator.clipboard.writeText(content);
|
|
1054
1423
|
setCopied(true);
|
|
@@ -1056,8 +1425,8 @@ function ChatExportToolbar({
|
|
|
1056
1425
|
onExported?.("markdown", toExport.length);
|
|
1057
1426
|
}, [toExport, onExported]);
|
|
1058
1427
|
const disabled = messages.length === 0;
|
|
1059
|
-
const [forking, setForking] =
|
|
1060
|
-
const handleFork =
|
|
1428
|
+
const [forking, setForking] = React6.useState(false);
|
|
1429
|
+
const handleFork = React6.useCallback(async (upToMessageId) => {
|
|
1061
1430
|
if (!onFork)
|
|
1062
1431
|
return;
|
|
1063
1432
|
setForking(true);
|
|
@@ -1067,35 +1436,35 @@ function ChatExportToolbar({
|
|
|
1067
1436
|
setForking(false);
|
|
1068
1437
|
}
|
|
1069
1438
|
}, [onFork]);
|
|
1070
|
-
return /* @__PURE__ */
|
|
1439
|
+
return /* @__PURE__ */ jsxs8("div", {
|
|
1071
1440
|
className: "flex items-center gap-2",
|
|
1072
1441
|
children: [
|
|
1073
|
-
onCreateNew && /* @__PURE__ */
|
|
1442
|
+
onCreateNew && /* @__PURE__ */ jsxs8(Button4, {
|
|
1074
1443
|
variant: "outline",
|
|
1075
1444
|
size: "sm",
|
|
1076
1445
|
onPress: onCreateNew,
|
|
1077
1446
|
"aria-label": "New conversation",
|
|
1078
1447
|
children: [
|
|
1079
|
-
/* @__PURE__ */
|
|
1448
|
+
/* @__PURE__ */ jsx8(Plus, {
|
|
1080
1449
|
className: "h-4 w-4"
|
|
1081
1450
|
}),
|
|
1082
1451
|
"New"
|
|
1083
1452
|
]
|
|
1084
1453
|
}),
|
|
1085
|
-
onFork && messages.length > 0 && /* @__PURE__ */
|
|
1454
|
+
onFork && messages.length > 0 && /* @__PURE__ */ jsxs8(Button4, {
|
|
1086
1455
|
variant: "outline",
|
|
1087
1456
|
size: "sm",
|
|
1088
1457
|
disabled: forking,
|
|
1089
1458
|
onPress: () => handleFork(),
|
|
1090
1459
|
"aria-label": "Fork conversation",
|
|
1091
1460
|
children: [
|
|
1092
|
-
/* @__PURE__ */
|
|
1461
|
+
/* @__PURE__ */ jsx8(GitFork, {
|
|
1093
1462
|
className: "h-4 w-4"
|
|
1094
1463
|
}),
|
|
1095
1464
|
"Fork"
|
|
1096
1465
|
]
|
|
1097
1466
|
}),
|
|
1098
|
-
showSelectionSummary && selectedCount > 0 && /* @__PURE__ */
|
|
1467
|
+
showSelectionSummary && selectedCount > 0 && /* @__PURE__ */ jsxs8("span", {
|
|
1099
1468
|
className: "text-muted-foreground text-sm",
|
|
1100
1469
|
children: [
|
|
1101
1470
|
selectedCount,
|
|
@@ -1104,16 +1473,16 @@ function ChatExportToolbar({
|
|
|
1104
1473
|
" selected"
|
|
1105
1474
|
]
|
|
1106
1475
|
}),
|
|
1107
|
-
onSelectAll && onClearSelection && totalCount > 0 && /* @__PURE__ */
|
|
1476
|
+
onSelectAll && onClearSelection && totalCount > 0 && /* @__PURE__ */ jsxs8(Fragment4, {
|
|
1108
1477
|
children: [
|
|
1109
|
-
/* @__PURE__ */
|
|
1478
|
+
/* @__PURE__ */ jsx8(Button4, {
|
|
1110
1479
|
variant: "ghost",
|
|
1111
1480
|
size: "sm",
|
|
1112
1481
|
onPress: onSelectAll,
|
|
1113
1482
|
className: "text-xs",
|
|
1114
1483
|
children: "Select all"
|
|
1115
1484
|
}),
|
|
1116
|
-
selectedCount > 0 && /* @__PURE__ */
|
|
1485
|
+
selectedCount > 0 && /* @__PURE__ */ jsx8(Button4, {
|
|
1117
1486
|
variant: "ghost",
|
|
1118
1487
|
size: "sm",
|
|
1119
1488
|
onPress: onClearSelection,
|
|
@@ -1122,64 +1491,64 @@ function ChatExportToolbar({
|
|
|
1122
1491
|
})
|
|
1123
1492
|
]
|
|
1124
1493
|
}),
|
|
1125
|
-
/* @__PURE__ */
|
|
1494
|
+
/* @__PURE__ */ jsxs8(DropdownMenu, {
|
|
1126
1495
|
children: [
|
|
1127
|
-
/* @__PURE__ */
|
|
1496
|
+
/* @__PURE__ */ jsx8(DropdownMenuTrigger, {
|
|
1128
1497
|
asChild: true,
|
|
1129
|
-
children: /* @__PURE__ */
|
|
1498
|
+
children: /* @__PURE__ */ jsxs8(Button4, {
|
|
1130
1499
|
variant: "outline",
|
|
1131
1500
|
size: "sm",
|
|
1132
1501
|
disabled,
|
|
1133
1502
|
"aria-label": selectedCount > 0 ? "Export selected messages" : "Export conversation",
|
|
1134
1503
|
children: [
|
|
1135
|
-
/* @__PURE__ */
|
|
1504
|
+
/* @__PURE__ */ jsx8(Download2, {
|
|
1136
1505
|
className: "h-4 w-4"
|
|
1137
1506
|
}),
|
|
1138
1507
|
"Export"
|
|
1139
1508
|
]
|
|
1140
1509
|
})
|
|
1141
1510
|
}),
|
|
1142
|
-
/* @__PURE__ */
|
|
1511
|
+
/* @__PURE__ */ jsxs8(DropdownMenuContent, {
|
|
1143
1512
|
align: "end",
|
|
1144
1513
|
children: [
|
|
1145
|
-
/* @__PURE__ */
|
|
1514
|
+
/* @__PURE__ */ jsxs8(DropdownMenuItem, {
|
|
1146
1515
|
onSelect: () => handleExport("markdown"),
|
|
1147
1516
|
disabled,
|
|
1148
1517
|
children: [
|
|
1149
|
-
/* @__PURE__ */
|
|
1518
|
+
/* @__PURE__ */ jsx8(FileText2, {
|
|
1150
1519
|
className: "h-4 w-4"
|
|
1151
1520
|
}),
|
|
1152
1521
|
"Export as Markdown (.md)"
|
|
1153
1522
|
]
|
|
1154
1523
|
}),
|
|
1155
|
-
/* @__PURE__ */
|
|
1524
|
+
/* @__PURE__ */ jsxs8(DropdownMenuItem, {
|
|
1156
1525
|
onSelect: () => handleExport("txt"),
|
|
1157
1526
|
disabled,
|
|
1158
1527
|
children: [
|
|
1159
|
-
/* @__PURE__ */
|
|
1528
|
+
/* @__PURE__ */ jsx8(FileText2, {
|
|
1160
1529
|
className: "h-4 w-4"
|
|
1161
1530
|
}),
|
|
1162
1531
|
"Export as Plain Text (.txt)"
|
|
1163
1532
|
]
|
|
1164
1533
|
}),
|
|
1165
|
-
/* @__PURE__ */
|
|
1534
|
+
/* @__PURE__ */ jsxs8(DropdownMenuItem, {
|
|
1166
1535
|
onSelect: () => handleExport("json"),
|
|
1167
1536
|
disabled,
|
|
1168
1537
|
children: [
|
|
1169
|
-
/* @__PURE__ */
|
|
1538
|
+
/* @__PURE__ */ jsx8(FileText2, {
|
|
1170
1539
|
className: "h-4 w-4"
|
|
1171
1540
|
}),
|
|
1172
1541
|
"Export as JSON (.json)"
|
|
1173
1542
|
]
|
|
1174
1543
|
}),
|
|
1175
|
-
/* @__PURE__ */
|
|
1176
|
-
/* @__PURE__ */
|
|
1544
|
+
/* @__PURE__ */ jsx8(DropdownMenuSeparator, {}),
|
|
1545
|
+
/* @__PURE__ */ jsxs8(DropdownMenuItem, {
|
|
1177
1546
|
onSelect: () => handleCopy(),
|
|
1178
1547
|
disabled,
|
|
1179
1548
|
children: [
|
|
1180
|
-
copied ? /* @__PURE__ */
|
|
1549
|
+
copied ? /* @__PURE__ */ jsx8(Check3, {
|
|
1181
1550
|
className: "h-4 w-4 text-green-500"
|
|
1182
|
-
}) : /* @__PURE__ */
|
|
1551
|
+
}) : /* @__PURE__ */ jsx8(Copy3, {
|
|
1183
1552
|
className: "h-4 w-4"
|
|
1184
1553
|
}),
|
|
1185
1554
|
copied ? "Copied to clipboard" : "Copy to clipboard"
|
|
@@ -1193,11 +1562,11 @@ function ChatExportToolbar({
|
|
|
1193
1562
|
});
|
|
1194
1563
|
}
|
|
1195
1564
|
// src/presentation/components/ChatWithExport.tsx
|
|
1196
|
-
import * as
|
|
1565
|
+
import * as React10 from "react";
|
|
1197
1566
|
|
|
1198
1567
|
// src/presentation/components/ThinkingLevelPicker.tsx
|
|
1199
|
-
import * as
|
|
1200
|
-
import { cn as
|
|
1568
|
+
import * as React7 from "react";
|
|
1569
|
+
import { cn as cn7 } from "@contractspec/lib.ui-kit-web/ui/utils";
|
|
1201
1570
|
import {
|
|
1202
1571
|
Select,
|
|
1203
1572
|
SelectContent,
|
|
@@ -1259,7 +1628,7 @@ function getProviderOptions(level, providerName) {
|
|
|
1259
1628
|
}
|
|
1260
1629
|
|
|
1261
1630
|
// src/presentation/components/ThinkingLevelPicker.tsx
|
|
1262
|
-
import { jsx as
|
|
1631
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1263
1632
|
"use client";
|
|
1264
1633
|
var THINKING_LEVELS = [
|
|
1265
1634
|
"instant",
|
|
@@ -1273,20 +1642,20 @@ function ThinkingLevelPicker({
|
|
|
1273
1642
|
className,
|
|
1274
1643
|
compact = false
|
|
1275
1644
|
}) {
|
|
1276
|
-
const handleChange =
|
|
1645
|
+
const handleChange = React7.useCallback((v) => {
|
|
1277
1646
|
onChange(v);
|
|
1278
1647
|
}, [onChange]);
|
|
1279
1648
|
if (compact) {
|
|
1280
|
-
return /* @__PURE__ */
|
|
1649
|
+
return /* @__PURE__ */ jsxs9(Select, {
|
|
1281
1650
|
value,
|
|
1282
1651
|
onValueChange: handleChange,
|
|
1283
1652
|
children: [
|
|
1284
|
-
/* @__PURE__ */
|
|
1285
|
-
className:
|
|
1286
|
-
children: /* @__PURE__ */
|
|
1653
|
+
/* @__PURE__ */ jsx9(SelectTrigger, {
|
|
1654
|
+
className: cn7("w-[140px]", className),
|
|
1655
|
+
children: /* @__PURE__ */ jsx9(SelectValue, {})
|
|
1287
1656
|
}),
|
|
1288
|
-
/* @__PURE__ */
|
|
1289
|
-
children: THINKING_LEVELS.map((level) => /* @__PURE__ */
|
|
1657
|
+
/* @__PURE__ */ jsx9(SelectContent, {
|
|
1658
|
+
children: THINKING_LEVELS.map((level) => /* @__PURE__ */ jsx9(SelectItem, {
|
|
1290
1659
|
value: level,
|
|
1291
1660
|
children: THINKING_LEVEL_LABELS[level]
|
|
1292
1661
|
}, level))
|
|
@@ -1294,26 +1663,26 @@ function ThinkingLevelPicker({
|
|
|
1294
1663
|
]
|
|
1295
1664
|
});
|
|
1296
1665
|
}
|
|
1297
|
-
return /* @__PURE__ */
|
|
1298
|
-
className:
|
|
1666
|
+
return /* @__PURE__ */ jsxs9("div", {
|
|
1667
|
+
className: cn7("flex flex-col gap-1.5", className),
|
|
1299
1668
|
children: [
|
|
1300
|
-
/* @__PURE__ */
|
|
1669
|
+
/* @__PURE__ */ jsx9(Label, {
|
|
1301
1670
|
htmlFor: "thinking-level-picker",
|
|
1302
1671
|
className: "text-sm font-medium",
|
|
1303
1672
|
children: "Thinking Level"
|
|
1304
1673
|
}),
|
|
1305
|
-
/* @__PURE__ */
|
|
1674
|
+
/* @__PURE__ */ jsxs9(Select, {
|
|
1306
1675
|
name: "thinking-level-picker",
|
|
1307
1676
|
value,
|
|
1308
1677
|
onValueChange: handleChange,
|
|
1309
1678
|
children: [
|
|
1310
|
-
/* @__PURE__ */
|
|
1311
|
-
children: /* @__PURE__ */
|
|
1679
|
+
/* @__PURE__ */ jsx9(SelectTrigger, {
|
|
1680
|
+
children: /* @__PURE__ */ jsx9(SelectValue, {
|
|
1312
1681
|
placeholder: "Select thinking level"
|
|
1313
1682
|
})
|
|
1314
1683
|
}),
|
|
1315
|
-
/* @__PURE__ */
|
|
1316
|
-
children: THINKING_LEVELS.map((level) => /* @__PURE__ */
|
|
1684
|
+
/* @__PURE__ */ jsx9(SelectContent, {
|
|
1685
|
+
children: THINKING_LEVELS.map((level) => /* @__PURE__ */ jsx9(SelectItem, {
|
|
1317
1686
|
value: level,
|
|
1318
1687
|
title: THINKING_LEVEL_DESCRIPTIONS[level],
|
|
1319
1688
|
children: THINKING_LEVEL_LABELS[level]
|
|
@@ -1326,12 +1695,12 @@ function ThinkingLevelPicker({
|
|
|
1326
1695
|
}
|
|
1327
1696
|
|
|
1328
1697
|
// src/presentation/hooks/useMessageSelection.ts
|
|
1329
|
-
import * as
|
|
1698
|
+
import * as React8 from "react";
|
|
1330
1699
|
"use client";
|
|
1331
1700
|
function useMessageSelection(messageIds) {
|
|
1332
|
-
const [selectedIds, setSelectedIds] =
|
|
1333
|
-
const idSet =
|
|
1334
|
-
|
|
1701
|
+
const [selectedIds, setSelectedIds] = React8.useState(() => new Set);
|
|
1702
|
+
const idSet = React8.useMemo(() => new Set(messageIds), [messageIds.join(",")]);
|
|
1703
|
+
React8.useEffect(() => {
|
|
1335
1704
|
setSelectedIds((prev) => {
|
|
1336
1705
|
const next = new Set;
|
|
1337
1706
|
for (const id of prev) {
|
|
@@ -1341,7 +1710,7 @@ function useMessageSelection(messageIds) {
|
|
|
1341
1710
|
return next.size === prev.size ? prev : next;
|
|
1342
1711
|
});
|
|
1343
1712
|
}, [idSet]);
|
|
1344
|
-
const toggle =
|
|
1713
|
+
const toggle = React8.useCallback((id) => {
|
|
1345
1714
|
setSelectedIds((prev) => {
|
|
1346
1715
|
const next = new Set(prev);
|
|
1347
1716
|
if (next.has(id))
|
|
@@ -1351,13 +1720,13 @@ function useMessageSelection(messageIds) {
|
|
|
1351
1720
|
return next;
|
|
1352
1721
|
});
|
|
1353
1722
|
}, []);
|
|
1354
|
-
const selectAll =
|
|
1723
|
+
const selectAll = React8.useCallback(() => {
|
|
1355
1724
|
setSelectedIds(new Set(messageIds));
|
|
1356
1725
|
}, [messageIds.join(",")]);
|
|
1357
|
-
const clearSelection =
|
|
1726
|
+
const clearSelection = React8.useCallback(() => {
|
|
1358
1727
|
setSelectedIds(new Set);
|
|
1359
1728
|
}, []);
|
|
1360
|
-
const isSelected =
|
|
1729
|
+
const isSelected = React8.useCallback((id) => selectedIds.has(id), [selectedIds]);
|
|
1361
1730
|
const selectedCount = selectedIds.size;
|
|
1362
1731
|
return {
|
|
1363
1732
|
selectedIds,
|
|
@@ -1369,8 +1738,38 @@ function useMessageSelection(messageIds) {
|
|
|
1369
1738
|
};
|
|
1370
1739
|
}
|
|
1371
1740
|
|
|
1741
|
+
// src/presentation/components/Suggestion.tsx
|
|
1742
|
+
import * as React9 from "react";
|
|
1743
|
+
import { Button as Button5 } from "@contractspec/lib.design-system";
|
|
1744
|
+
import { cn as cn8 } from "@contractspec/lib.ui-kit-web/ui/utils";
|
|
1745
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
1746
|
+
"use client";
|
|
1747
|
+
function Suggestions({ children, className }) {
|
|
1748
|
+
return /* @__PURE__ */ jsx10("div", {
|
|
1749
|
+
className: cn8("flex flex-wrap gap-2", className),
|
|
1750
|
+
children
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
function Suggestion({
|
|
1754
|
+
suggestion,
|
|
1755
|
+
onClick,
|
|
1756
|
+
className
|
|
1757
|
+
}) {
|
|
1758
|
+
const handleClick = React9.useCallback(() => {
|
|
1759
|
+
onClick?.(suggestion);
|
|
1760
|
+
}, [suggestion, onClick]);
|
|
1761
|
+
return /* @__PURE__ */ jsx10(Button5, {
|
|
1762
|
+
type: "button",
|
|
1763
|
+
variant: "outline",
|
|
1764
|
+
size: "sm",
|
|
1765
|
+
onPress: handleClick,
|
|
1766
|
+
className: cn8("text-muted-foreground hover:text-foreground", className),
|
|
1767
|
+
children: suggestion
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1372
1771
|
// src/presentation/components/ChatWithExport.tsx
|
|
1373
|
-
import { jsx as
|
|
1772
|
+
import { jsx as jsx11, jsxs as jsxs10, Fragment as Fragment5 } from "react/jsx-runtime";
|
|
1374
1773
|
"use client";
|
|
1375
1774
|
function ChatWithExport({
|
|
1376
1775
|
messages,
|
|
@@ -1386,20 +1785,27 @@ function ChatWithExport({
|
|
|
1386
1785
|
thinkingLevel = "thinking",
|
|
1387
1786
|
onThinkingLevelChange,
|
|
1388
1787
|
presentationRenderer,
|
|
1389
|
-
formRenderer
|
|
1788
|
+
formRenderer,
|
|
1789
|
+
dataViewRenderer,
|
|
1790
|
+
components,
|
|
1791
|
+
suggestions,
|
|
1792
|
+
onSuggestionClick,
|
|
1793
|
+
suggestionComponents: suggestionComps,
|
|
1794
|
+
showSuggestionsWhenEmpty = true
|
|
1390
1795
|
}) {
|
|
1391
|
-
const messageIds =
|
|
1796
|
+
const messageIds = React10.useMemo(() => messages.map((m) => m.id), [messages]);
|
|
1392
1797
|
const selection = useMessageSelection(messageIds);
|
|
1798
|
+
const showSuggestions = suggestions && suggestions.length > 0 && (messages.length === 0 || showSuggestionsWhenEmpty);
|
|
1393
1799
|
const hasToolbar = showExport || showMessageSelection;
|
|
1394
1800
|
const hasPicker = Boolean(onThinkingLevelChange);
|
|
1395
|
-
const headerContent = hasPicker || hasToolbar ? /* @__PURE__ */
|
|
1801
|
+
const headerContent = hasPicker || hasToolbar ? /* @__PURE__ */ jsxs10(Fragment5, {
|
|
1396
1802
|
children: [
|
|
1397
|
-
hasPicker && /* @__PURE__ */
|
|
1803
|
+
hasPicker && onThinkingLevelChange && /* @__PURE__ */ jsx11(ThinkingLevelPicker, {
|
|
1398
1804
|
value: thinkingLevel,
|
|
1399
1805
|
onChange: onThinkingLevelChange,
|
|
1400
1806
|
compact: true
|
|
1401
1807
|
}),
|
|
1402
|
-
hasToolbar && /* @__PURE__ */
|
|
1808
|
+
hasToolbar && /* @__PURE__ */ jsx11(ChatExportToolbar, {
|
|
1403
1809
|
messages,
|
|
1404
1810
|
conversation,
|
|
1405
1811
|
selectedIds: selection.selectedIds,
|
|
@@ -1413,12 +1819,12 @@ function ChatWithExport({
|
|
|
1413
1819
|
})
|
|
1414
1820
|
]
|
|
1415
1821
|
}) : null;
|
|
1416
|
-
return /* @__PURE__ */
|
|
1822
|
+
return /* @__PURE__ */ jsxs10(ChatContainer, {
|
|
1417
1823
|
className,
|
|
1418
1824
|
headerContent,
|
|
1419
1825
|
showScrollButton,
|
|
1420
1826
|
children: [
|
|
1421
|
-
messages.map((msg) => /* @__PURE__ */
|
|
1827
|
+
messages.map((msg) => /* @__PURE__ */ jsx11(ChatMessage, {
|
|
1422
1828
|
message: msg,
|
|
1423
1829
|
selectable: showMessageSelection,
|
|
1424
1830
|
selected: selection.isSelected(msg.id),
|
|
@@ -1426,26 +1832,47 @@ function ChatWithExport({
|
|
|
1426
1832
|
editable: msg.role === "user" && !!onEditMessage,
|
|
1427
1833
|
onEdit: onEditMessage,
|
|
1428
1834
|
presentationRenderer,
|
|
1429
|
-
formRenderer
|
|
1835
|
+
formRenderer,
|
|
1836
|
+
dataViewRenderer,
|
|
1837
|
+
components
|
|
1430
1838
|
}, msg.id)),
|
|
1839
|
+
showSuggestions && (() => {
|
|
1840
|
+
const SuggestionsComp = suggestionComps?.Suggestions;
|
|
1841
|
+
const SuggestionComp = suggestionComps?.Suggestion;
|
|
1842
|
+
if (SuggestionsComp && SuggestionComp) {
|
|
1843
|
+
return /* @__PURE__ */ jsx11(SuggestionsComp, {
|
|
1844
|
+
children: suggestions.map((s) => /* @__PURE__ */ jsx11(SuggestionComp, {
|
|
1845
|
+
suggestion: s,
|
|
1846
|
+
onClick: onSuggestionClick
|
|
1847
|
+
}, s))
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1850
|
+
return /* @__PURE__ */ jsx11(Suggestions, {
|
|
1851
|
+
className: "mb-4",
|
|
1852
|
+
children: suggestions.map((s) => /* @__PURE__ */ jsx11(Suggestion, {
|
|
1853
|
+
suggestion: s,
|
|
1854
|
+
onClick: onSuggestionClick
|
|
1855
|
+
}, s))
|
|
1856
|
+
});
|
|
1857
|
+
})(),
|
|
1431
1858
|
children
|
|
1432
1859
|
]
|
|
1433
1860
|
});
|
|
1434
1861
|
}
|
|
1435
1862
|
// src/presentation/components/ChatSidebar.tsx
|
|
1436
|
-
import * as
|
|
1863
|
+
import * as React12 from "react";
|
|
1437
1864
|
import { Plus as Plus2, Trash2, MessageSquare } from "lucide-react";
|
|
1438
|
-
import { Button as
|
|
1439
|
-
import { cn as
|
|
1865
|
+
import { Button as Button6 } from "@contractspec/lib.design-system";
|
|
1866
|
+
import { cn as cn9 } from "@contractspec/lib.ui-kit-web/ui/utils";
|
|
1440
1867
|
|
|
1441
1868
|
// src/presentation/hooks/useConversations.ts
|
|
1442
|
-
import * as
|
|
1869
|
+
import * as React11 from "react";
|
|
1443
1870
|
"use client";
|
|
1444
1871
|
function useConversations(options) {
|
|
1445
1872
|
const { store, projectId, tags, limit = 50 } = options;
|
|
1446
|
-
const [conversations, setConversations] =
|
|
1447
|
-
const [isLoading, setIsLoading] =
|
|
1448
|
-
const refresh =
|
|
1873
|
+
const [conversations, setConversations] = React11.useState([]);
|
|
1874
|
+
const [isLoading, setIsLoading] = React11.useState(true);
|
|
1875
|
+
const refresh = React11.useCallback(async () => {
|
|
1449
1876
|
setIsLoading(true);
|
|
1450
1877
|
try {
|
|
1451
1878
|
const list = await store.list({
|
|
@@ -1459,10 +1886,10 @@ function useConversations(options) {
|
|
|
1459
1886
|
setIsLoading(false);
|
|
1460
1887
|
}
|
|
1461
1888
|
}, [store, projectId, tags, limit]);
|
|
1462
|
-
|
|
1889
|
+
React11.useEffect(() => {
|
|
1463
1890
|
refresh();
|
|
1464
1891
|
}, [refresh]);
|
|
1465
|
-
const deleteConversation =
|
|
1892
|
+
const deleteConversation = React11.useCallback(async (id) => {
|
|
1466
1893
|
const ok = await store.delete(id);
|
|
1467
1894
|
if (ok) {
|
|
1468
1895
|
setConversations((prev) => prev.filter((c) => c.id !== id));
|
|
@@ -1478,7 +1905,7 @@ function useConversations(options) {
|
|
|
1478
1905
|
}
|
|
1479
1906
|
|
|
1480
1907
|
// src/presentation/components/ChatSidebar.tsx
|
|
1481
|
-
import { jsx as
|
|
1908
|
+
import { jsx as jsx12, jsxs as jsxs11, Fragment as Fragment6 } from "react/jsx-runtime";
|
|
1482
1909
|
"use client";
|
|
1483
1910
|
function formatDate(date) {
|
|
1484
1911
|
const d = new Date(date);
|
|
@@ -1500,7 +1927,7 @@ function ConversationItem({
|
|
|
1500
1927
|
}) {
|
|
1501
1928
|
const title = conversation.title ?? conversation.messages[0]?.content?.slice(0, 50) ?? "New chat";
|
|
1502
1929
|
const displayTitle = title.length > 40 ? `${title.slice(0, 40)}…` : title;
|
|
1503
|
-
return /* @__PURE__ */
|
|
1930
|
+
return /* @__PURE__ */ jsxs11("div", {
|
|
1504
1931
|
role: "button",
|
|
1505
1932
|
tabIndex: 0,
|
|
1506
1933
|
onClick: onSelect,
|
|
@@ -1510,24 +1937,24 @@ function ConversationItem({
|
|
|
1510
1937
|
onSelect();
|
|
1511
1938
|
}
|
|
1512
1939
|
},
|
|
1513
|
-
className:
|
|
1940
|
+
className: cn9("group flex cursor-pointer items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors", selected ? "bg-accent text-accent-foreground" : "hover:bg-accent/50"),
|
|
1514
1941
|
children: [
|
|
1515
|
-
/* @__PURE__ */
|
|
1942
|
+
/* @__PURE__ */ jsx12(MessageSquare, {
|
|
1516
1943
|
className: "text-muted-foreground h-4 w-4 shrink-0"
|
|
1517
1944
|
}),
|
|
1518
|
-
/* @__PURE__ */
|
|
1945
|
+
/* @__PURE__ */ jsxs11("div", {
|
|
1519
1946
|
className: "min-w-0 flex-1",
|
|
1520
1947
|
children: [
|
|
1521
|
-
/* @__PURE__ */
|
|
1948
|
+
/* @__PURE__ */ jsx12("p", {
|
|
1522
1949
|
className: "truncate",
|
|
1523
1950
|
children: displayTitle
|
|
1524
1951
|
}),
|
|
1525
|
-
/* @__PURE__ */
|
|
1952
|
+
/* @__PURE__ */ jsxs11("p", {
|
|
1526
1953
|
className: "text-muted-foreground text-xs",
|
|
1527
1954
|
children: [
|
|
1528
1955
|
formatDate(conversation.updatedAt),
|
|
1529
1956
|
conversation.projectName && ` · ${conversation.projectName}`,
|
|
1530
|
-
conversation.tags && conversation.tags.length > 0 && /* @__PURE__ */
|
|
1957
|
+
conversation.tags && conversation.tags.length > 0 && /* @__PURE__ */ jsxs11(Fragment6, {
|
|
1531
1958
|
children: [
|
|
1532
1959
|
" · ",
|
|
1533
1960
|
conversation.tags.slice(0, 2).join(", ")
|
|
@@ -1537,15 +1964,17 @@ function ConversationItem({
|
|
|
1537
1964
|
})
|
|
1538
1965
|
]
|
|
1539
1966
|
}),
|
|
1540
|
-
/* @__PURE__ */
|
|
1967
|
+
/* @__PURE__ */ jsx12("span", {
|
|
1968
|
+
role: "group",
|
|
1541
1969
|
onClick: (e) => e.stopPropagation(),
|
|
1542
|
-
|
|
1970
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
1971
|
+
children: /* @__PURE__ */ jsx12(Button6, {
|
|
1543
1972
|
variant: "ghost",
|
|
1544
1973
|
size: "sm",
|
|
1545
1974
|
className: "h-6 w-6 shrink-0 p-0 opacity-0 group-hover:opacity-100",
|
|
1546
1975
|
onPress: onDelete,
|
|
1547
1976
|
"aria-label": "Delete conversation",
|
|
1548
|
-
children: /* @__PURE__ */
|
|
1977
|
+
children: /* @__PURE__ */ jsx12(Trash2, {
|
|
1549
1978
|
className: "h-3 w-3"
|
|
1550
1979
|
})
|
|
1551
1980
|
})
|
|
@@ -1566,8 +1995,13 @@ function ChatSidebar({
|
|
|
1566
1995
|
onUpdateConversation,
|
|
1567
1996
|
selectedConversation
|
|
1568
1997
|
}) {
|
|
1569
|
-
const { conversations, isLoading,
|
|
1570
|
-
|
|
1998
|
+
const { conversations, isLoading, deleteConversation } = useConversations({
|
|
1999
|
+
store,
|
|
2000
|
+
projectId,
|
|
2001
|
+
tags,
|
|
2002
|
+
limit
|
|
2003
|
+
});
|
|
2004
|
+
const handleDelete = React12.useCallback(async (id) => {
|
|
1571
2005
|
const ok = await deleteConversation(id);
|
|
1572
2006
|
if (ok && selectedConversationId === id) {
|
|
1573
2007
|
onSelectConversation(null);
|
|
@@ -1575,39 +2009,39 @@ function ChatSidebar({
|
|
|
1575
2009
|
}, [deleteConversation, selectedConversationId, onSelectConversation]);
|
|
1576
2010
|
if (collapsed)
|
|
1577
2011
|
return null;
|
|
1578
|
-
return /* @__PURE__ */
|
|
1579
|
-
className:
|
|
2012
|
+
return /* @__PURE__ */ jsxs11("div", {
|
|
2013
|
+
className: cn9("border-border flex w-64 shrink-0 flex-col border-r", className),
|
|
1580
2014
|
children: [
|
|
1581
|
-
/* @__PURE__ */
|
|
2015
|
+
/* @__PURE__ */ jsxs11("div", {
|
|
1582
2016
|
className: "border-border flex shrink-0 items-center justify-between border-b p-2",
|
|
1583
2017
|
children: [
|
|
1584
|
-
/* @__PURE__ */
|
|
2018
|
+
/* @__PURE__ */ jsx12("span", {
|
|
1585
2019
|
className: "text-muted-foreground text-sm font-medium",
|
|
1586
2020
|
children: "Conversations"
|
|
1587
2021
|
}),
|
|
1588
|
-
/* @__PURE__ */
|
|
2022
|
+
/* @__PURE__ */ jsx12(Button6, {
|
|
1589
2023
|
variant: "ghost",
|
|
1590
2024
|
size: "sm",
|
|
1591
2025
|
className: "h-8 w-8 p-0",
|
|
1592
2026
|
onPress: onCreateNew,
|
|
1593
2027
|
"aria-label": "New conversation",
|
|
1594
|
-
children: /* @__PURE__ */
|
|
2028
|
+
children: /* @__PURE__ */ jsx12(Plus2, {
|
|
1595
2029
|
className: "h-4 w-4"
|
|
1596
2030
|
})
|
|
1597
2031
|
})
|
|
1598
2032
|
]
|
|
1599
2033
|
}),
|
|
1600
|
-
/* @__PURE__ */
|
|
2034
|
+
/* @__PURE__ */ jsx12("div", {
|
|
1601
2035
|
className: "flex-1 overflow-y-auto p-2",
|
|
1602
|
-
children: isLoading ? /* @__PURE__ */
|
|
2036
|
+
children: isLoading ? /* @__PURE__ */ jsx12("div", {
|
|
1603
2037
|
className: "text-muted-foreground py-4 text-center text-sm",
|
|
1604
2038
|
children: "Loading…"
|
|
1605
|
-
}) : conversations.length === 0 ? /* @__PURE__ */
|
|
2039
|
+
}) : conversations.length === 0 ? /* @__PURE__ */ jsx12("div", {
|
|
1606
2040
|
className: "text-muted-foreground py-4 text-center text-sm",
|
|
1607
2041
|
children: "No conversations yet"
|
|
1608
|
-
}) : /* @__PURE__ */
|
|
2042
|
+
}) : /* @__PURE__ */ jsx12("div", {
|
|
1609
2043
|
className: "flex flex-col gap-1",
|
|
1610
|
-
children: conversations.map((conv) => /* @__PURE__ */
|
|
2044
|
+
children: conversations.map((conv) => /* @__PURE__ */ jsx12(ConversationItem, {
|
|
1611
2045
|
conversation: conv,
|
|
1612
2046
|
selected: conv.id === selectedConversationId,
|
|
1613
2047
|
onSelect: () => onSelectConversation(conv.id),
|
|
@@ -1615,7 +2049,7 @@ function ChatSidebar({
|
|
|
1615
2049
|
}, conv.id))
|
|
1616
2050
|
})
|
|
1617
2051
|
}),
|
|
1618
|
-
selectedConversation && onUpdateConversation && /* @__PURE__ */
|
|
2052
|
+
selectedConversation && onUpdateConversation && /* @__PURE__ */ jsx12(ConversationMeta, {
|
|
1619
2053
|
conversation: selectedConversation,
|
|
1620
2054
|
onUpdate: onUpdateConversation
|
|
1621
2055
|
})
|
|
@@ -1626,13 +2060,13 @@ function ConversationMeta({
|
|
|
1626
2060
|
conversation,
|
|
1627
2061
|
onUpdate
|
|
1628
2062
|
}) {
|
|
1629
|
-
const [projectName, setProjectName] =
|
|
1630
|
-
const [tagsStr, setTagsStr] =
|
|
1631
|
-
|
|
2063
|
+
const [projectName, setProjectName] = React12.useState(conversation.projectName ?? "");
|
|
2064
|
+
const [tagsStr, setTagsStr] = React12.useState(conversation.tags?.join(", ") ?? "");
|
|
2065
|
+
React12.useEffect(() => {
|
|
1632
2066
|
setProjectName(conversation.projectName ?? "");
|
|
1633
2067
|
setTagsStr(conversation.tags?.join(", ") ?? "");
|
|
1634
2068
|
}, [conversation.id, conversation.projectName, conversation.tags]);
|
|
1635
|
-
const handleBlur =
|
|
2069
|
+
const handleBlur = React12.useCallback(() => {
|
|
1636
2070
|
const tags = tagsStr.split(",").map((t) => t.trim()).filter(Boolean);
|
|
1637
2071
|
if (projectName !== (conversation.projectName ?? "") || JSON.stringify(tags) !== JSON.stringify(conversation.tags ?? [])) {
|
|
1638
2072
|
onUpdate(conversation.id, {
|
|
@@ -1649,14 +2083,14 @@ function ConversationMeta({
|
|
|
1649
2083
|
tagsStr,
|
|
1650
2084
|
onUpdate
|
|
1651
2085
|
]);
|
|
1652
|
-
return /* @__PURE__ */
|
|
2086
|
+
return /* @__PURE__ */ jsxs11("div", {
|
|
1653
2087
|
className: "border-border shrink-0 border-t p-2",
|
|
1654
2088
|
children: [
|
|
1655
|
-
/* @__PURE__ */
|
|
2089
|
+
/* @__PURE__ */ jsx12("p", {
|
|
1656
2090
|
className: "text-muted-foreground mb-1 text-xs font-medium",
|
|
1657
2091
|
children: "Project"
|
|
1658
2092
|
}),
|
|
1659
|
-
/* @__PURE__ */
|
|
2093
|
+
/* @__PURE__ */ jsx12("input", {
|
|
1660
2094
|
type: "text",
|
|
1661
2095
|
value: projectName,
|
|
1662
2096
|
onChange: (e) => setProjectName(e.target.value),
|
|
@@ -1664,11 +2098,11 @@ function ConversationMeta({
|
|
|
1664
2098
|
placeholder: "Project name",
|
|
1665
2099
|
className: "border-input bg-background mb-2 w-full rounded px-2 py-1 text-xs"
|
|
1666
2100
|
}),
|
|
1667
|
-
/* @__PURE__ */
|
|
2101
|
+
/* @__PURE__ */ jsx12("p", {
|
|
1668
2102
|
className: "text-muted-foreground mb-1 text-xs font-medium",
|
|
1669
2103
|
children: "Tags"
|
|
1670
2104
|
}),
|
|
1671
|
-
/* @__PURE__ */
|
|
2105
|
+
/* @__PURE__ */ jsx12("input", {
|
|
1672
2106
|
type: "text",
|
|
1673
2107
|
value: tagsStr,
|
|
1674
2108
|
onChange: (e) => setTagsStr(e.target.value),
|
|
@@ -1680,10 +2114,10 @@ function ConversationMeta({
|
|
|
1680
2114
|
});
|
|
1681
2115
|
}
|
|
1682
2116
|
// src/presentation/components/ChatWithSidebar.tsx
|
|
1683
|
-
import * as
|
|
2117
|
+
import * as React14 from "react";
|
|
1684
2118
|
|
|
1685
2119
|
// src/presentation/hooks/useChat.tsx
|
|
1686
|
-
import * as
|
|
2120
|
+
import * as React13 from "react";
|
|
1687
2121
|
import { tool as tool4 } from "ai";
|
|
1688
2122
|
import { z as z4 } from "zod";
|
|
1689
2123
|
|
|
@@ -2757,16 +3191,16 @@ function useChat(options = {}) {
|
|
|
2757
3191
|
mcpServers,
|
|
2758
3192
|
agentMode
|
|
2759
3193
|
} = options;
|
|
2760
|
-
const [messages, setMessages] =
|
|
2761
|
-
const [mcpTools, setMcpTools] =
|
|
2762
|
-
const mcpCleanupRef =
|
|
2763
|
-
const [conversation, setConversation] =
|
|
2764
|
-
const [isLoading, setIsLoading] =
|
|
2765
|
-
const [error, setError] =
|
|
2766
|
-
const [conversationId, setConversationId] =
|
|
2767
|
-
const abortControllerRef =
|
|
2768
|
-
const chatServiceRef =
|
|
2769
|
-
|
|
3194
|
+
const [messages, setMessages] = React13.useState([]);
|
|
3195
|
+
const [mcpTools, setMcpTools] = React13.useState(null);
|
|
3196
|
+
const mcpCleanupRef = React13.useRef(null);
|
|
3197
|
+
const [conversation, setConversation] = React13.useState(null);
|
|
3198
|
+
const [isLoading, setIsLoading] = React13.useState(false);
|
|
3199
|
+
const [error, setError] = React13.useState(null);
|
|
3200
|
+
const [conversationId, setConversationId] = React13.useState(initialConversationId ?? null);
|
|
3201
|
+
const abortControllerRef = React13.useRef(null);
|
|
3202
|
+
const chatServiceRef = React13.useRef(null);
|
|
3203
|
+
React13.useEffect(() => {
|
|
2770
3204
|
if (!mcpServers?.length) {
|
|
2771
3205
|
setMcpTools(null);
|
|
2772
3206
|
return;
|
|
@@ -2798,7 +3232,7 @@ function useChat(options = {}) {
|
|
|
2798
3232
|
setMcpTools(null);
|
|
2799
3233
|
};
|
|
2800
3234
|
}, [mcpServers]);
|
|
2801
|
-
|
|
3235
|
+
React13.useEffect(() => {
|
|
2802
3236
|
const chatProvider = createProvider({
|
|
2803
3237
|
provider,
|
|
2804
3238
|
model,
|
|
@@ -2835,7 +3269,7 @@ function useChat(options = {}) {
|
|
|
2835
3269
|
surfacePlanConfig,
|
|
2836
3270
|
mcpTools
|
|
2837
3271
|
]);
|
|
2838
|
-
|
|
3272
|
+
React13.useEffect(() => {
|
|
2839
3273
|
if (!conversationId || !chatServiceRef.current)
|
|
2840
3274
|
return;
|
|
2841
3275
|
const loadConversation = async () => {
|
|
@@ -2849,7 +3283,7 @@ function useChat(options = {}) {
|
|
|
2849
3283
|
};
|
|
2850
3284
|
loadConversation().catch(console.error);
|
|
2851
3285
|
}, [conversationId]);
|
|
2852
|
-
const sendMessage =
|
|
3286
|
+
const sendMessage = React13.useCallback(async (content, attachments, opts) => {
|
|
2853
3287
|
if (agentMode?.agent) {
|
|
2854
3288
|
setIsLoading(true);
|
|
2855
3289
|
setError(null);
|
|
@@ -3071,14 +3505,21 @@ function useChat(options = {}) {
|
|
|
3071
3505
|
agentMode,
|
|
3072
3506
|
store
|
|
3073
3507
|
]);
|
|
3074
|
-
const clearConversation =
|
|
3508
|
+
const clearConversation = React13.useCallback(() => {
|
|
3075
3509
|
setMessages([]);
|
|
3076
3510
|
setConversation(null);
|
|
3077
3511
|
setConversationId(null);
|
|
3078
3512
|
setError(null);
|
|
3079
3513
|
}, []);
|
|
3080
|
-
const regenerate =
|
|
3081
|
-
|
|
3514
|
+
const regenerate = React13.useCallback(async () => {
|
|
3515
|
+
let lastUserMessageIndex = -1;
|
|
3516
|
+
for (let i = messages.length - 1;i >= 0; i--) {
|
|
3517
|
+
const m = messages[i];
|
|
3518
|
+
if (m?.role === "user") {
|
|
3519
|
+
lastUserMessageIndex = i;
|
|
3520
|
+
break;
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3082
3523
|
if (lastUserMessageIndex === -1)
|
|
3083
3524
|
return;
|
|
3084
3525
|
const lastUserMessage = messages[lastUserMessageIndex];
|
|
@@ -3087,12 +3528,12 @@ function useChat(options = {}) {
|
|
|
3087
3528
|
setMessages((prev) => prev.slice(0, lastUserMessageIndex + 1));
|
|
3088
3529
|
await sendMessage(lastUserMessage.content, lastUserMessage.attachments);
|
|
3089
3530
|
}, [messages, sendMessage]);
|
|
3090
|
-
const stop =
|
|
3531
|
+
const stop = React13.useCallback(() => {
|
|
3091
3532
|
abortControllerRef.current?.abort();
|
|
3092
3533
|
setIsLoading(false);
|
|
3093
3534
|
}, []);
|
|
3094
3535
|
const createNewConversation = clearConversation;
|
|
3095
|
-
const editMessage =
|
|
3536
|
+
const editMessage = React13.useCallback(async (messageId, newContent) => {
|
|
3096
3537
|
if (!chatServiceRef.current || !conversationId)
|
|
3097
3538
|
return;
|
|
3098
3539
|
const msg = messages.find((m) => m.id === messageId);
|
|
@@ -3107,7 +3548,7 @@ function useChat(options = {}) {
|
|
|
3107
3548
|
}
|
|
3108
3549
|
await sendMessage(newContent, undefined, { skipUserAppend: true });
|
|
3109
3550
|
}, [conversationId, messages, sendMessage]);
|
|
3110
|
-
const forkConversation =
|
|
3551
|
+
const forkConversation = React13.useCallback(async (upToMessageId) => {
|
|
3111
3552
|
if (!chatServiceRef.current)
|
|
3112
3553
|
return null;
|
|
3113
3554
|
const idToFork = conversationId ?? conversation?.id;
|
|
@@ -3123,7 +3564,7 @@ function useChat(options = {}) {
|
|
|
3123
3564
|
return null;
|
|
3124
3565
|
}
|
|
3125
3566
|
}, [conversationId, conversation]);
|
|
3126
|
-
const updateConversationFn =
|
|
3567
|
+
const updateConversationFn = React13.useCallback(async (updates) => {
|
|
3127
3568
|
if (!chatServiceRef.current || !conversationId)
|
|
3128
3569
|
return null;
|
|
3129
3570
|
const updated = await chatServiceRef.current.updateConversation(conversationId, updates);
|
|
@@ -3131,7 +3572,7 @@ function useChat(options = {}) {
|
|
|
3131
3572
|
setConversation(updated);
|
|
3132
3573
|
return updated;
|
|
3133
3574
|
}, [conversationId]);
|
|
3134
|
-
const addToolApprovalResponse =
|
|
3575
|
+
const addToolApprovalResponse = React13.useCallback((_toolCallId, _result) => {
|
|
3135
3576
|
throw new Error(`addToolApprovalResponse: Tool approval requires server route with toUIMessageStreamResponse. ` + `Use createChatRoute and @ai-sdk/react useChat for tools with requireApproval.`);
|
|
3136
3577
|
}, []);
|
|
3137
3578
|
const hasApprovalTools = toolsDefs?.some((t) => t.requireApproval) ?? false;
|
|
@@ -3382,7 +3823,7 @@ function createLocalStorageConversationStore(storageKey) {
|
|
|
3382
3823
|
}
|
|
3383
3824
|
|
|
3384
3825
|
// src/presentation/components/ChatWithSidebar.tsx
|
|
3385
|
-
import { jsx as
|
|
3826
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3386
3827
|
"use client";
|
|
3387
3828
|
var defaultStore = createLocalStorageConversationStore();
|
|
3388
3829
|
function ChatWithSidebar({
|
|
@@ -3393,10 +3834,15 @@ function ChatWithSidebar({
|
|
|
3393
3834
|
thinkingLevel: initialThinkingLevel = "thinking",
|
|
3394
3835
|
presentationRenderer,
|
|
3395
3836
|
formRenderer,
|
|
3837
|
+
dataViewRenderer,
|
|
3838
|
+
components,
|
|
3839
|
+
suggestions,
|
|
3840
|
+
suggestionComponents,
|
|
3841
|
+
showSuggestionsWhenEmpty = false,
|
|
3396
3842
|
...useChatOptions
|
|
3397
3843
|
}) {
|
|
3398
3844
|
const effectiveStore = store;
|
|
3399
|
-
const [thinkingLevel, setThinkingLevel] =
|
|
3845
|
+
const [thinkingLevel, setThinkingLevel] = React14.useState(initialThinkingLevel);
|
|
3400
3846
|
const chat = useChat({
|
|
3401
3847
|
...useChatOptions,
|
|
3402
3848
|
store: effectiveStore,
|
|
@@ -3414,13 +3860,16 @@ function ChatWithSidebar({
|
|
|
3414
3860
|
updateConversation
|
|
3415
3861
|
} = chat;
|
|
3416
3862
|
const selectedConversationId = conversation?.id ?? null;
|
|
3417
|
-
const handleSelectConversation =
|
|
3863
|
+
const handleSelectConversation = React14.useCallback((id) => {
|
|
3418
3864
|
setConversationId(id);
|
|
3419
3865
|
}, [setConversationId]);
|
|
3420
|
-
|
|
3866
|
+
const handleSuggestionClick = React14.useCallback((suggestion) => {
|
|
3867
|
+
sendMessage(suggestion);
|
|
3868
|
+
}, [sendMessage]);
|
|
3869
|
+
return /* @__PURE__ */ jsxs12("div", {
|
|
3421
3870
|
className: className ?? "flex h-full w-full",
|
|
3422
3871
|
children: [
|
|
3423
|
-
/* @__PURE__ */
|
|
3872
|
+
/* @__PURE__ */ jsx13(ChatSidebar, {
|
|
3424
3873
|
store: effectiveStore,
|
|
3425
3874
|
selectedConversationId,
|
|
3426
3875
|
onSelectConversation: handleSelectConversation,
|
|
@@ -3434,9 +3883,9 @@ function ChatWithSidebar({
|
|
|
3434
3883
|
}
|
|
3435
3884
|
} : undefined
|
|
3436
3885
|
}),
|
|
3437
|
-
/* @__PURE__ */
|
|
3886
|
+
/* @__PURE__ */ jsx13("div", {
|
|
3438
3887
|
className: "flex min-w-0 flex-1 flex-col",
|
|
3439
|
-
children: /* @__PURE__ */
|
|
3888
|
+
children: /* @__PURE__ */ jsx13(ChatWithExport, {
|
|
3440
3889
|
messages,
|
|
3441
3890
|
conversation,
|
|
3442
3891
|
onCreateNew: createNewConversation,
|
|
@@ -3446,7 +3895,13 @@ function ChatWithSidebar({
|
|
|
3446
3895
|
onThinkingLevelChange: setThinkingLevel,
|
|
3447
3896
|
presentationRenderer,
|
|
3448
3897
|
formRenderer,
|
|
3449
|
-
|
|
3898
|
+
dataViewRenderer,
|
|
3899
|
+
components,
|
|
3900
|
+
suggestions,
|
|
3901
|
+
onSuggestionClick: handleSuggestionClick,
|
|
3902
|
+
suggestionComponents,
|
|
3903
|
+
showSuggestionsWhenEmpty,
|
|
3904
|
+
children: /* @__PURE__ */ jsx13(ChatInput, {
|
|
3450
3905
|
onSend: (content, att) => sendMessage(content, att),
|
|
3451
3906
|
disabled: isLoading,
|
|
3452
3907
|
isLoading
|
|
@@ -3457,9 +3912,9 @@ function ChatWithSidebar({
|
|
|
3457
3912
|
});
|
|
3458
3913
|
}
|
|
3459
3914
|
// src/presentation/components/ModelPicker.tsx
|
|
3460
|
-
import * as
|
|
3461
|
-
import { cn as
|
|
3462
|
-
import { Button as
|
|
3915
|
+
import * as React15 from "react";
|
|
3916
|
+
import { cn as cn10 } from "@contractspec/lib.ui-kit-web/ui/utils";
|
|
3917
|
+
import { Button as Button7 } from "@contractspec/lib.design-system";
|
|
3463
3918
|
import {
|
|
3464
3919
|
Select as Select2,
|
|
3465
3920
|
SelectContent as SelectContent2,
|
|
@@ -3473,22 +3928,22 @@ import { Bot as Bot2, Cloud, Cpu, Sparkles } from "lucide-react";
|
|
|
3473
3928
|
import {
|
|
3474
3929
|
getModelsForProvider
|
|
3475
3930
|
} from "@contractspec/lib.ai-providers";
|
|
3476
|
-
import { jsx as
|
|
3931
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3477
3932
|
"use client";
|
|
3478
3933
|
var PROVIDER_ICONS = {
|
|
3479
|
-
ollama: /* @__PURE__ */
|
|
3934
|
+
ollama: /* @__PURE__ */ jsx14(Cpu, {
|
|
3480
3935
|
className: "h-4 w-4"
|
|
3481
3936
|
}),
|
|
3482
|
-
openai: /* @__PURE__ */
|
|
3937
|
+
openai: /* @__PURE__ */ jsx14(Bot2, {
|
|
3483
3938
|
className: "h-4 w-4"
|
|
3484
3939
|
}),
|
|
3485
|
-
anthropic: /* @__PURE__ */
|
|
3940
|
+
anthropic: /* @__PURE__ */ jsx14(Sparkles, {
|
|
3486
3941
|
className: "h-4 w-4"
|
|
3487
3942
|
}),
|
|
3488
|
-
mistral: /* @__PURE__ */
|
|
3943
|
+
mistral: /* @__PURE__ */ jsx14(Cloud, {
|
|
3489
3944
|
className: "h-4 w-4"
|
|
3490
3945
|
}),
|
|
3491
|
-
gemini: /* @__PURE__ */
|
|
3946
|
+
gemini: /* @__PURE__ */ jsx14(Sparkles, {
|
|
3492
3947
|
className: "h-4 w-4"
|
|
3493
3948
|
})
|
|
3494
3949
|
};
|
|
@@ -3520,7 +3975,7 @@ function ModelPicker({
|
|
|
3520
3975
|
];
|
|
3521
3976
|
const models = getModelsForProvider(value.provider);
|
|
3522
3977
|
const selectedModel = models.find((m) => m.id === value.model);
|
|
3523
|
-
const handleProviderChange =
|
|
3978
|
+
const handleProviderChange = React15.useCallback((providerName) => {
|
|
3524
3979
|
const provider = providerName;
|
|
3525
3980
|
const providerInfo = providers.find((p) => p.provider === provider);
|
|
3526
3981
|
const providerModels = getModelsForProvider(provider);
|
|
@@ -3531,33 +3986,33 @@ function ModelPicker({
|
|
|
3531
3986
|
mode: providerInfo?.mode ?? "byok"
|
|
3532
3987
|
});
|
|
3533
3988
|
}, [onChange, providers]);
|
|
3534
|
-
const handleModelChange =
|
|
3989
|
+
const handleModelChange = React15.useCallback((modelId) => {
|
|
3535
3990
|
onChange({
|
|
3536
3991
|
...value,
|
|
3537
3992
|
model: modelId
|
|
3538
3993
|
});
|
|
3539
3994
|
}, [onChange, value]);
|
|
3540
3995
|
if (compact) {
|
|
3541
|
-
return /* @__PURE__ */
|
|
3542
|
-
className:
|
|
3996
|
+
return /* @__PURE__ */ jsxs13("div", {
|
|
3997
|
+
className: cn10("flex items-center gap-2", className),
|
|
3543
3998
|
children: [
|
|
3544
|
-
/* @__PURE__ */
|
|
3999
|
+
/* @__PURE__ */ jsxs13(Select2, {
|
|
3545
4000
|
value: value.provider,
|
|
3546
4001
|
onValueChange: handleProviderChange,
|
|
3547
4002
|
children: [
|
|
3548
|
-
/* @__PURE__ */
|
|
4003
|
+
/* @__PURE__ */ jsx14(SelectTrigger2, {
|
|
3549
4004
|
className: "w-[140px]",
|
|
3550
|
-
children: /* @__PURE__ */
|
|
4005
|
+
children: /* @__PURE__ */ jsx14(SelectValue2, {})
|
|
3551
4006
|
}),
|
|
3552
|
-
/* @__PURE__ */
|
|
3553
|
-
children: providers.map((p) => /* @__PURE__ */
|
|
4007
|
+
/* @__PURE__ */ jsx14(SelectContent2, {
|
|
4008
|
+
children: providers.map((p) => /* @__PURE__ */ jsx14(SelectItem2, {
|
|
3554
4009
|
value: p.provider,
|
|
3555
4010
|
disabled: !p.available,
|
|
3556
|
-
children: /* @__PURE__ */
|
|
4011
|
+
children: /* @__PURE__ */ jsxs13("div", {
|
|
3557
4012
|
className: "flex items-center gap-2",
|
|
3558
4013
|
children: [
|
|
3559
4014
|
PROVIDER_ICONS[p.provider],
|
|
3560
|
-
/* @__PURE__ */
|
|
4015
|
+
/* @__PURE__ */ jsx14("span", {
|
|
3561
4016
|
children: PROVIDER_NAMES[p.provider]
|
|
3562
4017
|
})
|
|
3563
4018
|
]
|
|
@@ -3566,16 +4021,16 @@ function ModelPicker({
|
|
|
3566
4021
|
})
|
|
3567
4022
|
]
|
|
3568
4023
|
}),
|
|
3569
|
-
/* @__PURE__ */
|
|
4024
|
+
/* @__PURE__ */ jsxs13(Select2, {
|
|
3570
4025
|
value: value.model,
|
|
3571
4026
|
onValueChange: handleModelChange,
|
|
3572
4027
|
children: [
|
|
3573
|
-
/* @__PURE__ */
|
|
4028
|
+
/* @__PURE__ */ jsx14(SelectTrigger2, {
|
|
3574
4029
|
className: "w-[160px]",
|
|
3575
|
-
children: /* @__PURE__ */
|
|
4030
|
+
children: /* @__PURE__ */ jsx14(SelectValue2, {})
|
|
3576
4031
|
}),
|
|
3577
|
-
/* @__PURE__ */
|
|
3578
|
-
children: models.map((m) => /* @__PURE__ */
|
|
4032
|
+
/* @__PURE__ */ jsx14(SelectContent2, {
|
|
4033
|
+
children: models.map((m) => /* @__PURE__ */ jsx14(SelectItem2, {
|
|
3579
4034
|
value: m.id,
|
|
3580
4035
|
children: m.name
|
|
3581
4036
|
}, m.id))
|
|
@@ -3585,32 +4040,32 @@ function ModelPicker({
|
|
|
3585
4040
|
]
|
|
3586
4041
|
});
|
|
3587
4042
|
}
|
|
3588
|
-
return /* @__PURE__ */
|
|
3589
|
-
className:
|
|
4043
|
+
return /* @__PURE__ */ jsxs13("div", {
|
|
4044
|
+
className: cn10("flex flex-col gap-3", className),
|
|
3590
4045
|
children: [
|
|
3591
|
-
/* @__PURE__ */
|
|
4046
|
+
/* @__PURE__ */ jsxs13("div", {
|
|
3592
4047
|
className: "flex flex-col gap-1.5",
|
|
3593
4048
|
children: [
|
|
3594
|
-
/* @__PURE__ */
|
|
4049
|
+
/* @__PURE__ */ jsx14(Label2, {
|
|
3595
4050
|
htmlFor: "provider-selection",
|
|
3596
4051
|
className: "text-sm font-medium",
|
|
3597
4052
|
children: "Provider"
|
|
3598
4053
|
}),
|
|
3599
|
-
/* @__PURE__ */
|
|
4054
|
+
/* @__PURE__ */ jsx14("div", {
|
|
3600
4055
|
className: "flex flex-wrap gap-2",
|
|
3601
4056
|
id: "provider-selection",
|
|
3602
|
-
children: providers.map((p) => /* @__PURE__ */
|
|
4057
|
+
children: providers.map((p) => /* @__PURE__ */ jsxs13(Button7, {
|
|
3603
4058
|
variant: value.provider === p.provider ? "default" : "outline",
|
|
3604
4059
|
size: "sm",
|
|
3605
4060
|
onPress: () => p.available && handleProviderChange(p.provider),
|
|
3606
4061
|
disabled: !p.available,
|
|
3607
|
-
className:
|
|
4062
|
+
className: cn10(!p.available && "opacity-50"),
|
|
3608
4063
|
children: [
|
|
3609
4064
|
PROVIDER_ICONS[p.provider],
|
|
3610
|
-
/* @__PURE__ */
|
|
4065
|
+
/* @__PURE__ */ jsx14("span", {
|
|
3611
4066
|
children: PROVIDER_NAMES[p.provider]
|
|
3612
4067
|
}),
|
|
3613
|
-
/* @__PURE__ */
|
|
4068
|
+
/* @__PURE__ */ jsx14(Badge, {
|
|
3614
4069
|
variant: MODE_BADGES[p.mode].variant,
|
|
3615
4070
|
className: "ml-1",
|
|
3616
4071
|
children: MODE_BADGES[p.mode].label
|
|
@@ -3620,46 +4075,46 @@ function ModelPicker({
|
|
|
3620
4075
|
})
|
|
3621
4076
|
]
|
|
3622
4077
|
}),
|
|
3623
|
-
/* @__PURE__ */
|
|
4078
|
+
/* @__PURE__ */ jsxs13("div", {
|
|
3624
4079
|
className: "flex flex-col gap-1.5",
|
|
3625
4080
|
children: [
|
|
3626
|
-
/* @__PURE__ */
|
|
4081
|
+
/* @__PURE__ */ jsx14(Label2, {
|
|
3627
4082
|
htmlFor: "model-picker",
|
|
3628
4083
|
className: "text-sm font-medium",
|
|
3629
4084
|
children: "Model"
|
|
3630
4085
|
}),
|
|
3631
|
-
/* @__PURE__ */
|
|
4086
|
+
/* @__PURE__ */ jsxs13(Select2, {
|
|
3632
4087
|
name: "model-picker",
|
|
3633
4088
|
value: value.model,
|
|
3634
4089
|
onValueChange: handleModelChange,
|
|
3635
4090
|
children: [
|
|
3636
|
-
/* @__PURE__ */
|
|
3637
|
-
children: /* @__PURE__ */
|
|
4091
|
+
/* @__PURE__ */ jsx14(SelectTrigger2, {
|
|
4092
|
+
children: /* @__PURE__ */ jsx14(SelectValue2, {
|
|
3638
4093
|
placeholder: "Select a model"
|
|
3639
4094
|
})
|
|
3640
4095
|
}),
|
|
3641
|
-
/* @__PURE__ */
|
|
3642
|
-
children: models.map((m) => /* @__PURE__ */
|
|
4096
|
+
/* @__PURE__ */ jsx14(SelectContent2, {
|
|
4097
|
+
children: models.map((m) => /* @__PURE__ */ jsx14(SelectItem2, {
|
|
3643
4098
|
value: m.id,
|
|
3644
|
-
children: /* @__PURE__ */
|
|
4099
|
+
children: /* @__PURE__ */ jsxs13("div", {
|
|
3645
4100
|
className: "flex items-center gap-2",
|
|
3646
4101
|
children: [
|
|
3647
|
-
/* @__PURE__ */
|
|
4102
|
+
/* @__PURE__ */ jsx14("span", {
|
|
3648
4103
|
children: m.name
|
|
3649
4104
|
}),
|
|
3650
|
-
/* @__PURE__ */
|
|
4105
|
+
/* @__PURE__ */ jsxs13("span", {
|
|
3651
4106
|
className: "text-muted-foreground text-xs",
|
|
3652
4107
|
children: [
|
|
3653
4108
|
Math.round(m.contextWindow / 1000),
|
|
3654
4109
|
"K"
|
|
3655
4110
|
]
|
|
3656
4111
|
}),
|
|
3657
|
-
m.capabilities.vision && /* @__PURE__ */
|
|
4112
|
+
m.capabilities.vision && /* @__PURE__ */ jsx14(Badge, {
|
|
3658
4113
|
variant: "outline",
|
|
3659
4114
|
className: "text-xs",
|
|
3660
4115
|
children: "Vision"
|
|
3661
4116
|
}),
|
|
3662
|
-
m.capabilities.reasoning && /* @__PURE__ */
|
|
4117
|
+
m.capabilities.reasoning && /* @__PURE__ */ jsx14(Badge, {
|
|
3663
4118
|
variant: "outline",
|
|
3664
4119
|
className: "text-xs",
|
|
3665
4120
|
children: "Reasoning"
|
|
@@ -3672,23 +4127,23 @@ function ModelPicker({
|
|
|
3672
4127
|
})
|
|
3673
4128
|
]
|
|
3674
4129
|
}),
|
|
3675
|
-
selectedModel && /* @__PURE__ */
|
|
4130
|
+
selectedModel && /* @__PURE__ */ jsxs13("div", {
|
|
3676
4131
|
className: "text-muted-foreground flex flex-wrap gap-2 text-xs",
|
|
3677
4132
|
children: [
|
|
3678
|
-
/* @__PURE__ */
|
|
4133
|
+
/* @__PURE__ */ jsxs13("span", {
|
|
3679
4134
|
children: [
|
|
3680
4135
|
"Context: ",
|
|
3681
4136
|
Math.round(selectedModel.contextWindow / 1000),
|
|
3682
4137
|
"K tokens"
|
|
3683
4138
|
]
|
|
3684
4139
|
}),
|
|
3685
|
-
selectedModel.capabilities.vision && /* @__PURE__ */
|
|
4140
|
+
selectedModel.capabilities.vision && /* @__PURE__ */ jsx14("span", {
|
|
3686
4141
|
children: "• Vision"
|
|
3687
4142
|
}),
|
|
3688
|
-
selectedModel.capabilities.tools && /* @__PURE__ */
|
|
4143
|
+
selectedModel.capabilities.tools && /* @__PURE__ */ jsx14("span", {
|
|
3689
4144
|
children: "• Tools"
|
|
3690
4145
|
}),
|
|
3691
|
-
selectedModel.capabilities.reasoning && /* @__PURE__ */
|
|
4146
|
+
selectedModel.capabilities.reasoning && /* @__PURE__ */ jsx14("span", {
|
|
3692
4147
|
children: "• Reasoning"
|
|
3693
4148
|
})
|
|
3694
4149
|
]
|
|
@@ -3697,7 +4152,7 @@ function ModelPicker({
|
|
|
3697
4152
|
});
|
|
3698
4153
|
}
|
|
3699
4154
|
// src/presentation/components/ContextIndicator.tsx
|
|
3700
|
-
import { cn as
|
|
4155
|
+
import { cn as cn11 } from "@contractspec/lib.ui-kit-web/ui/utils";
|
|
3701
4156
|
import { Badge as Badge2 } from "@contractspec/lib.ui-kit-web/ui/badge";
|
|
3702
4157
|
import {
|
|
3703
4158
|
Tooltip,
|
|
@@ -3706,7 +4161,7 @@ import {
|
|
|
3706
4161
|
TooltipTrigger
|
|
3707
4162
|
} from "@contractspec/lib.ui-kit-web/ui/tooltip";
|
|
3708
4163
|
import { FolderOpen, FileCode, Zap, Info } from "lucide-react";
|
|
3709
|
-
import { jsx as
|
|
4164
|
+
import { jsx as jsx15, jsxs as jsxs14, Fragment as Fragment7 } from "react/jsx-runtime";
|
|
3710
4165
|
"use client";
|
|
3711
4166
|
function ContextIndicator({
|
|
3712
4167
|
summary,
|
|
@@ -3715,51 +4170,51 @@ function ContextIndicator({
|
|
|
3715
4170
|
showDetails = true
|
|
3716
4171
|
}) {
|
|
3717
4172
|
if (!summary && !active) {
|
|
3718
|
-
return /* @__PURE__ */
|
|
3719
|
-
className:
|
|
4173
|
+
return /* @__PURE__ */ jsxs14("div", {
|
|
4174
|
+
className: cn11("flex items-center gap-1.5 text-sm", "text-muted-foreground", className),
|
|
3720
4175
|
children: [
|
|
3721
|
-
/* @__PURE__ */
|
|
4176
|
+
/* @__PURE__ */ jsx15(Info, {
|
|
3722
4177
|
className: "h-4 w-4"
|
|
3723
4178
|
}),
|
|
3724
|
-
/* @__PURE__ */
|
|
4179
|
+
/* @__PURE__ */ jsx15("span", {
|
|
3725
4180
|
children: "No workspace context"
|
|
3726
4181
|
})
|
|
3727
4182
|
]
|
|
3728
4183
|
});
|
|
3729
4184
|
}
|
|
3730
|
-
const content = /* @__PURE__ */
|
|
3731
|
-
className:
|
|
4185
|
+
const content = /* @__PURE__ */ jsxs14("div", {
|
|
4186
|
+
className: cn11("flex items-center gap-2", active ? "text-foreground" : "text-muted-foreground", className),
|
|
3732
4187
|
children: [
|
|
3733
|
-
/* @__PURE__ */
|
|
4188
|
+
/* @__PURE__ */ jsxs14(Badge2, {
|
|
3734
4189
|
variant: active ? "default" : "secondary",
|
|
3735
4190
|
className: "flex items-center gap-1",
|
|
3736
4191
|
children: [
|
|
3737
|
-
/* @__PURE__ */
|
|
4192
|
+
/* @__PURE__ */ jsx15(Zap, {
|
|
3738
4193
|
className: "h-3 w-3"
|
|
3739
4194
|
}),
|
|
3740
4195
|
"Context"
|
|
3741
4196
|
]
|
|
3742
4197
|
}),
|
|
3743
|
-
summary && showDetails && /* @__PURE__ */
|
|
4198
|
+
summary && showDetails && /* @__PURE__ */ jsxs14(Fragment7, {
|
|
3744
4199
|
children: [
|
|
3745
|
-
/* @__PURE__ */
|
|
4200
|
+
/* @__PURE__ */ jsxs14("div", {
|
|
3746
4201
|
className: "flex items-center gap-1 text-xs",
|
|
3747
4202
|
children: [
|
|
3748
|
-
/* @__PURE__ */
|
|
4203
|
+
/* @__PURE__ */ jsx15(FolderOpen, {
|
|
3749
4204
|
className: "h-3.5 w-3.5"
|
|
3750
4205
|
}),
|
|
3751
|
-
/* @__PURE__ */
|
|
4206
|
+
/* @__PURE__ */ jsx15("span", {
|
|
3752
4207
|
children: summary.name
|
|
3753
4208
|
})
|
|
3754
4209
|
]
|
|
3755
4210
|
}),
|
|
3756
|
-
/* @__PURE__ */
|
|
4211
|
+
/* @__PURE__ */ jsxs14("div", {
|
|
3757
4212
|
className: "flex items-center gap-1 text-xs",
|
|
3758
4213
|
children: [
|
|
3759
|
-
/* @__PURE__ */
|
|
4214
|
+
/* @__PURE__ */ jsx15(FileCode, {
|
|
3760
4215
|
className: "h-3.5 w-3.5"
|
|
3761
4216
|
}),
|
|
3762
|
-
/* @__PURE__ */
|
|
4217
|
+
/* @__PURE__ */ jsxs14("span", {
|
|
3763
4218
|
children: [
|
|
3764
4219
|
summary.specs.total,
|
|
3765
4220
|
" specs"
|
|
@@ -3774,77 +4229,77 @@ function ContextIndicator({
|
|
|
3774
4229
|
if (!summary) {
|
|
3775
4230
|
return content;
|
|
3776
4231
|
}
|
|
3777
|
-
return /* @__PURE__ */
|
|
3778
|
-
children: /* @__PURE__ */
|
|
4232
|
+
return /* @__PURE__ */ jsx15(TooltipProvider, {
|
|
4233
|
+
children: /* @__PURE__ */ jsxs14(Tooltip, {
|
|
3779
4234
|
children: [
|
|
3780
|
-
/* @__PURE__ */
|
|
4235
|
+
/* @__PURE__ */ jsx15(TooltipTrigger, {
|
|
3781
4236
|
asChild: true,
|
|
3782
4237
|
children: content
|
|
3783
4238
|
}),
|
|
3784
|
-
/* @__PURE__ */
|
|
4239
|
+
/* @__PURE__ */ jsx15(TooltipContent, {
|
|
3785
4240
|
side: "bottom",
|
|
3786
4241
|
className: "max-w-[300px]",
|
|
3787
|
-
children: /* @__PURE__ */
|
|
4242
|
+
children: /* @__PURE__ */ jsxs14("div", {
|
|
3788
4243
|
className: "flex flex-col gap-2 text-sm",
|
|
3789
4244
|
children: [
|
|
3790
|
-
/* @__PURE__ */
|
|
4245
|
+
/* @__PURE__ */ jsx15("div", {
|
|
3791
4246
|
className: "font-medium",
|
|
3792
4247
|
children: summary.name
|
|
3793
4248
|
}),
|
|
3794
|
-
/* @__PURE__ */
|
|
4249
|
+
/* @__PURE__ */ jsx15("div", {
|
|
3795
4250
|
className: "text-muted-foreground text-xs",
|
|
3796
4251
|
children: summary.path
|
|
3797
4252
|
}),
|
|
3798
|
-
/* @__PURE__ */
|
|
4253
|
+
/* @__PURE__ */ jsx15("div", {
|
|
3799
4254
|
className: "border-t pt-2",
|
|
3800
|
-
children: /* @__PURE__ */
|
|
4255
|
+
children: /* @__PURE__ */ jsxs14("div", {
|
|
3801
4256
|
className: "grid grid-cols-2 gap-1 text-xs",
|
|
3802
4257
|
children: [
|
|
3803
|
-
/* @__PURE__ */
|
|
4258
|
+
/* @__PURE__ */ jsx15("span", {
|
|
3804
4259
|
children: "Commands:"
|
|
3805
4260
|
}),
|
|
3806
|
-
/* @__PURE__ */
|
|
4261
|
+
/* @__PURE__ */ jsx15("span", {
|
|
3807
4262
|
className: "text-right",
|
|
3808
4263
|
children: summary.specs.commands
|
|
3809
4264
|
}),
|
|
3810
|
-
/* @__PURE__ */
|
|
4265
|
+
/* @__PURE__ */ jsx15("span", {
|
|
3811
4266
|
children: "Queries:"
|
|
3812
4267
|
}),
|
|
3813
|
-
/* @__PURE__ */
|
|
4268
|
+
/* @__PURE__ */ jsx15("span", {
|
|
3814
4269
|
className: "text-right",
|
|
3815
4270
|
children: summary.specs.queries
|
|
3816
4271
|
}),
|
|
3817
|
-
/* @__PURE__ */
|
|
4272
|
+
/* @__PURE__ */ jsx15("span", {
|
|
3818
4273
|
children: "Events:"
|
|
3819
4274
|
}),
|
|
3820
|
-
/* @__PURE__ */
|
|
4275
|
+
/* @__PURE__ */ jsx15("span", {
|
|
3821
4276
|
className: "text-right",
|
|
3822
4277
|
children: summary.specs.events
|
|
3823
4278
|
}),
|
|
3824
|
-
/* @__PURE__ */
|
|
4279
|
+
/* @__PURE__ */ jsx15("span", {
|
|
3825
4280
|
children: "Presentations:"
|
|
3826
4281
|
}),
|
|
3827
|
-
/* @__PURE__ */
|
|
4282
|
+
/* @__PURE__ */ jsx15("span", {
|
|
3828
4283
|
className: "text-right",
|
|
3829
4284
|
children: summary.specs.presentations
|
|
3830
4285
|
})
|
|
3831
4286
|
]
|
|
3832
4287
|
})
|
|
3833
4288
|
}),
|
|
3834
|
-
/* @__PURE__ */
|
|
4289
|
+
/* @__PURE__ */ jsxs14("div", {
|
|
3835
4290
|
className: "border-t pt-2 text-xs",
|
|
3836
4291
|
children: [
|
|
3837
|
-
/* @__PURE__ */
|
|
4292
|
+
/* @__PURE__ */ jsxs14("span", {
|
|
3838
4293
|
children: [
|
|
3839
4294
|
summary.files.total,
|
|
3840
4295
|
" files"
|
|
3841
4296
|
]
|
|
3842
4297
|
}),
|
|
3843
|
-
/* @__PURE__ */
|
|
4298
|
+
/* @__PURE__ */ jsx15("span", {
|
|
3844
4299
|
className: "mx-1",
|
|
3845
4300
|
children: "•"
|
|
3846
4301
|
}),
|
|
3847
|
-
/* @__PURE__ */
|
|
4302
|
+
/* @__PURE__ */ jsxs14("span", {
|
|
3848
4303
|
children: [
|
|
3849
4304
|
summary.files.specFiles,
|
|
3850
4305
|
" spec files"
|
|
@@ -3859,17 +4314,104 @@ function ContextIndicator({
|
|
|
3859
4314
|
})
|
|
3860
4315
|
});
|
|
3861
4316
|
}
|
|
4317
|
+
// src/presentation/components/ChainOfThought.tsx
|
|
4318
|
+
import {
|
|
4319
|
+
Collapsible as Collapsible3,
|
|
4320
|
+
CollapsibleContent as CollapsibleContent3,
|
|
4321
|
+
CollapsibleTrigger as CollapsibleTrigger3
|
|
4322
|
+
} from "@contractspec/lib.ui-kit-web/ui/collapsible";
|
|
4323
|
+
import { cn as cn12 } from "@contractspec/lib.ui-kit-web/ui/utils";
|
|
4324
|
+
import { ChevronDown, Dot } from "lucide-react";
|
|
4325
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
4326
|
+
"use client";
|
|
4327
|
+
function ChainOfThought({
|
|
4328
|
+
children,
|
|
4329
|
+
open,
|
|
4330
|
+
defaultOpen = false,
|
|
4331
|
+
onOpenChange,
|
|
4332
|
+
className
|
|
4333
|
+
}) {
|
|
4334
|
+
return /* @__PURE__ */ jsx16(Collapsible3, {
|
|
4335
|
+
open,
|
|
4336
|
+
defaultOpen,
|
|
4337
|
+
onOpenChange,
|
|
4338
|
+
className: cn12("group/cot mt-2", className),
|
|
4339
|
+
children
|
|
4340
|
+
});
|
|
4341
|
+
}
|
|
4342
|
+
function ChainOfThoughtHeader({
|
|
4343
|
+
children = "Chain of Thought",
|
|
4344
|
+
className
|
|
4345
|
+
}) {
|
|
4346
|
+
return /* @__PURE__ */ jsxs15(CollapsibleTrigger3, {
|
|
4347
|
+
className: cn12("hover:bg-muted flex w-full cursor-pointer items-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors", className),
|
|
4348
|
+
children: [
|
|
4349
|
+
/* @__PURE__ */ jsx16(ChevronDown, {
|
|
4350
|
+
className: "text-muted-foreground h-4 w-4 shrink-0 transition-transform group-data-[state=open]/cot:rotate-180"
|
|
4351
|
+
}),
|
|
4352
|
+
children
|
|
4353
|
+
]
|
|
4354
|
+
});
|
|
4355
|
+
}
|
|
4356
|
+
function ChainOfThoughtStep({
|
|
4357
|
+
label,
|
|
4358
|
+
description,
|
|
4359
|
+
status = "complete",
|
|
4360
|
+
icon: Icon = Dot,
|
|
4361
|
+
children,
|
|
4362
|
+
className
|
|
4363
|
+
}) {
|
|
4364
|
+
return /* @__PURE__ */ jsxs15("div", {
|
|
4365
|
+
className: cn12("border-border flex gap-3 border-b py-2 last:border-b-0", className),
|
|
4366
|
+
children: [
|
|
4367
|
+
/* @__PURE__ */ jsx16("div", {
|
|
4368
|
+
className: cn12("mt-1.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full", status === "complete" && "bg-green-500/20 text-green-700 dark:text-green-400", status === "active" && "bg-blue-500/20 text-blue-700 dark:text-blue-400", status === "pending" && "bg-muted text-muted-foreground"),
|
|
4369
|
+
children: /* @__PURE__ */ jsx16(Icon, {
|
|
4370
|
+
className: "h-3 w-3"
|
|
4371
|
+
})
|
|
4372
|
+
}),
|
|
4373
|
+
/* @__PURE__ */ jsxs15("div", {
|
|
4374
|
+
className: "min-w-0 flex-1",
|
|
4375
|
+
children: [
|
|
4376
|
+
/* @__PURE__ */ jsx16("p", {
|
|
4377
|
+
className: "font-medium",
|
|
4378
|
+
children: label
|
|
4379
|
+
}),
|
|
4380
|
+
description && /* @__PURE__ */ jsx16("p", {
|
|
4381
|
+
className: "text-muted-foreground mt-0.5 text-xs",
|
|
4382
|
+
children: description
|
|
4383
|
+
}),
|
|
4384
|
+
children && /* @__PURE__ */ jsx16("div", {
|
|
4385
|
+
className: "mt-2",
|
|
4386
|
+
children
|
|
4387
|
+
})
|
|
4388
|
+
]
|
|
4389
|
+
})
|
|
4390
|
+
]
|
|
4391
|
+
});
|
|
4392
|
+
}
|
|
4393
|
+
function ChainOfThoughtContent({
|
|
4394
|
+
children,
|
|
4395
|
+
className
|
|
4396
|
+
}) {
|
|
4397
|
+
return /* @__PURE__ */ jsx16(CollapsibleContent3, {
|
|
4398
|
+
children: /* @__PURE__ */ jsx16("div", {
|
|
4399
|
+
className: cn12("bg-muted border-border mt-1 rounded-md border px-3 py-2", className),
|
|
4400
|
+
children
|
|
4401
|
+
})
|
|
4402
|
+
});
|
|
4403
|
+
}
|
|
3862
4404
|
// src/presentation/hooks/useProviders.tsx
|
|
3863
|
-
import * as
|
|
4405
|
+
import * as React16 from "react";
|
|
3864
4406
|
import {
|
|
3865
4407
|
getAvailableProviders,
|
|
3866
4408
|
getModelsForProvider as getModelsForProvider2
|
|
3867
4409
|
} from "@contractspec/lib.ai-providers";
|
|
3868
4410
|
"use client";
|
|
3869
4411
|
function useProviders() {
|
|
3870
|
-
const [providers, setProviders] =
|
|
3871
|
-
const [isLoading, setIsLoading] =
|
|
3872
|
-
const loadProviders =
|
|
4412
|
+
const [providers, setProviders] = React16.useState([]);
|
|
4413
|
+
const [isLoading, setIsLoading] = React16.useState(true);
|
|
4414
|
+
const loadProviders = React16.useCallback(async () => {
|
|
3873
4415
|
setIsLoading(true);
|
|
3874
4416
|
try {
|
|
3875
4417
|
const available = getAvailableProviders();
|
|
@@ -3884,12 +4426,12 @@ function useProviders() {
|
|
|
3884
4426
|
setIsLoading(false);
|
|
3885
4427
|
}
|
|
3886
4428
|
}, []);
|
|
3887
|
-
|
|
4429
|
+
React16.useEffect(() => {
|
|
3888
4430
|
loadProviders();
|
|
3889
4431
|
}, [loadProviders]);
|
|
3890
|
-
const availableProviders =
|
|
3891
|
-
const isAvailable =
|
|
3892
|
-
const getModelsCallback =
|
|
4432
|
+
const availableProviders = React16.useMemo(() => providers.filter((p) => p.available), [providers]);
|
|
4433
|
+
const isAvailable = React16.useCallback((provider) => providers.some((p) => p.provider === provider && p.available), [providers]);
|
|
4434
|
+
const getModelsCallback = React16.useCallback((provider) => providers.find((p) => p.provider === provider)?.models ?? [], [providers]);
|
|
3893
4435
|
return {
|
|
3894
4436
|
providers,
|
|
3895
4437
|
availableProviders,
|
|
@@ -3910,8 +4452,18 @@ export {
|
|
|
3910
4452
|
useChat,
|
|
3911
4453
|
isPresentationToolResult,
|
|
3912
4454
|
isFormToolResult,
|
|
4455
|
+
isDataViewToolResult,
|
|
3913
4456
|
ToolResultRenderer,
|
|
3914
4457
|
ThinkingLevelPicker,
|
|
4458
|
+
Suggestions,
|
|
4459
|
+
Suggestion,
|
|
4460
|
+
SourcesTrigger,
|
|
4461
|
+
SourcesContent,
|
|
4462
|
+
Sources,
|
|
4463
|
+
Source,
|
|
4464
|
+
ReasoningTrigger,
|
|
4465
|
+
ReasoningContent,
|
|
4466
|
+
Reasoning,
|
|
3915
4467
|
ModelPicker,
|
|
3916
4468
|
ContextIndicator,
|
|
3917
4469
|
CodePreview,
|
|
@@ -3921,5 +4473,9 @@ export {
|
|
|
3921
4473
|
ChatMessage,
|
|
3922
4474
|
ChatInput,
|
|
3923
4475
|
ChatExportToolbar,
|
|
3924
|
-
ChatContainer
|
|
4476
|
+
ChatContainer,
|
|
4477
|
+
ChainOfThoughtStep,
|
|
4478
|
+
ChainOfThoughtHeader,
|
|
4479
|
+
ChainOfThoughtContent,
|
|
4480
|
+
ChainOfThought
|
|
3925
4481
|
};
|