@slipstream-ui/ai 0.3.0 → 0.5.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/dist/index.d.mts +33 -1
- package/dist/index.d.ts +33 -1
- package/dist/index.js +236 -110
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +238 -112
- package/dist/index.mjs.map +1 -1
- package/dist/manifests/attachment.manifest.json +2 -0
- package/dist/manifests/branch.manifest.json +2 -0
- package/dist/manifests/code-block.manifest.json +2 -0
- package/dist/manifests/command-palette.manifest.json +37 -3
- package/dist/manifests/confirmation.manifest.json +2 -0
- package/dist/manifests/inline-citation.manifest.json +2 -0
- package/dist/manifests/message-actions.manifest.json +3 -0
- package/dist/manifests/reasoning.manifest.json +6 -0
- package/dist/manifests/response.manifest.json +2 -0
- package/dist/manifests/tool-call.manifest.json +6 -0
- package/package.json +3 -3
- package/src/components/code-block/CodeBlock.tsx +91 -5
- package/src/components/command-palette/CommandPalette.test.tsx +21 -0
- package/src/components/command-palette/CommandPalette.tsx +71 -6
- package/src/components/confirmation/Confirmation.tsx +1 -1
- package/src/components/conversation/Conversation.tsx +6 -1
- package/src/components/reasoning/Reasoning.tsx +13 -6
- package/src/components/tool-call/ToolCall.tsx +24 -8
- package/src/manifests/attachment.manifest.json +2 -0
- package/src/manifests/branch.manifest.json +2 -0
- package/src/manifests/code-block.manifest.json +2 -0
- package/src/manifests/command-palette.manifest.json +37 -3
- package/src/manifests/confirmation.manifest.json +2 -0
- package/src/manifests/inline-citation.manifest.json +2 -0
- package/src/manifests/message-actions.manifest.json +3 -0
- package/src/manifests/reasoning.manifest.json +6 -0
- package/src/manifests/response.manifest.json +2 -0
- package/src/manifests/tool-call.manifest.json +6 -0
package/dist/index.d.mts
CHANGED
|
@@ -409,6 +409,13 @@ type ReasoningProps = {
|
|
|
409
409
|
duration?: number | string;
|
|
410
410
|
/** Marks reasoning as still arriving: animated header state. */
|
|
411
411
|
isStreaming?: boolean;
|
|
412
|
+
/** Localized header, count and step labels. */
|
|
413
|
+
labels?: {
|
|
414
|
+
title?: string;
|
|
415
|
+
count?: (count: number) => string;
|
|
416
|
+
thinking?: string;
|
|
417
|
+
step?: (index: number) => string;
|
|
418
|
+
};
|
|
412
419
|
};
|
|
413
420
|
declare const Reasoning: React.ForwardRefExoticComponent<ReasoningProps & React.RefAttributes<HTMLDivElement>>;
|
|
414
421
|
|
|
@@ -416,6 +423,16 @@ type ToolCallProps = {
|
|
|
416
423
|
toolCall: ToolCall$1;
|
|
417
424
|
className?: string;
|
|
418
425
|
showResult?: boolean;
|
|
426
|
+
/** Localized status and section labels. */
|
|
427
|
+
labels?: {
|
|
428
|
+
pending?: string;
|
|
429
|
+
running?: string;
|
|
430
|
+
completed?: string;
|
|
431
|
+
failed?: string;
|
|
432
|
+
arguments?: string;
|
|
433
|
+
result?: string;
|
|
434
|
+
error?: string;
|
|
435
|
+
};
|
|
419
436
|
};
|
|
420
437
|
/**
|
|
421
438
|
* Displays a single tool invocation: name, status chip, serialized
|
|
@@ -488,12 +505,27 @@ type Command = {
|
|
|
488
505
|
/** Extra lexical search terms. */
|
|
489
506
|
keywords?: string[];
|
|
490
507
|
shortcut?: string;
|
|
508
|
+
/** Optional leading icon (rendered by the default row or renderCommand). */
|
|
509
|
+
icon?: React.ReactNode;
|
|
510
|
+
/** Optional secondary line in the default row. */
|
|
511
|
+
description?: string;
|
|
491
512
|
};
|
|
492
513
|
type CommandPaletteProps = {
|
|
493
514
|
open: boolean;
|
|
494
515
|
onOpenChange: (open: boolean) => void;
|
|
516
|
+
/** Static command set (ignored for filtering when loadCommands is set). */
|
|
495
517
|
commands: Command[];
|
|
496
518
|
onSelect: (command: Command) => void;
|
|
519
|
+
/** Async source; called with the current query (debounced). */
|
|
520
|
+
loadCommands?: (query: string) => Promise<Command[]>;
|
|
521
|
+
/** Debounce for loadCommands, in ms. Default 200. */
|
|
522
|
+
debounceMs?: number;
|
|
523
|
+
/** Custom row renderer (icons, type badges, metadata). */
|
|
524
|
+
renderCommand?: (command: Command, state: {
|
|
525
|
+
active: boolean;
|
|
526
|
+
}) => React.ReactNode;
|
|
527
|
+
/** Shown while async commands load. */
|
|
528
|
+
loadingText?: string;
|
|
497
529
|
placeholder?: string;
|
|
498
530
|
};
|
|
499
531
|
/**
|
|
@@ -501,7 +533,7 @@ type CommandPaletteProps = {
|
|
|
501
533
|
* keyboard navigation, lexical filtering over label/keywords, and
|
|
502
534
|
* Escape-to-close. No focus leaves the input while navigating.
|
|
503
535
|
*/
|
|
504
|
-
declare function CommandPalette({ open, onOpenChange, commands, onSelect, placeholder, }: CommandPaletteProps): React.JSX.Element | null;
|
|
536
|
+
declare function CommandPalette({ open, onOpenChange, commands, onSelect, loadCommands, debounceMs, renderCommand, loadingText, placeholder, }: CommandPaletteProps): React.JSX.Element | null;
|
|
505
537
|
|
|
506
538
|
/**
|
|
507
539
|
* Structural types mirroring the parts of the Vercel AI SDK's chat state the
|
package/dist/index.d.ts
CHANGED
|
@@ -409,6 +409,13 @@ type ReasoningProps = {
|
|
|
409
409
|
duration?: number | string;
|
|
410
410
|
/** Marks reasoning as still arriving: animated header state. */
|
|
411
411
|
isStreaming?: boolean;
|
|
412
|
+
/** Localized header, count and step labels. */
|
|
413
|
+
labels?: {
|
|
414
|
+
title?: string;
|
|
415
|
+
count?: (count: number) => string;
|
|
416
|
+
thinking?: string;
|
|
417
|
+
step?: (index: number) => string;
|
|
418
|
+
};
|
|
412
419
|
};
|
|
413
420
|
declare const Reasoning: React.ForwardRefExoticComponent<ReasoningProps & React.RefAttributes<HTMLDivElement>>;
|
|
414
421
|
|
|
@@ -416,6 +423,16 @@ type ToolCallProps = {
|
|
|
416
423
|
toolCall: ToolCall$1;
|
|
417
424
|
className?: string;
|
|
418
425
|
showResult?: boolean;
|
|
426
|
+
/** Localized status and section labels. */
|
|
427
|
+
labels?: {
|
|
428
|
+
pending?: string;
|
|
429
|
+
running?: string;
|
|
430
|
+
completed?: string;
|
|
431
|
+
failed?: string;
|
|
432
|
+
arguments?: string;
|
|
433
|
+
result?: string;
|
|
434
|
+
error?: string;
|
|
435
|
+
};
|
|
419
436
|
};
|
|
420
437
|
/**
|
|
421
438
|
* Displays a single tool invocation: name, status chip, serialized
|
|
@@ -488,12 +505,27 @@ type Command = {
|
|
|
488
505
|
/** Extra lexical search terms. */
|
|
489
506
|
keywords?: string[];
|
|
490
507
|
shortcut?: string;
|
|
508
|
+
/** Optional leading icon (rendered by the default row or renderCommand). */
|
|
509
|
+
icon?: React.ReactNode;
|
|
510
|
+
/** Optional secondary line in the default row. */
|
|
511
|
+
description?: string;
|
|
491
512
|
};
|
|
492
513
|
type CommandPaletteProps = {
|
|
493
514
|
open: boolean;
|
|
494
515
|
onOpenChange: (open: boolean) => void;
|
|
516
|
+
/** Static command set (ignored for filtering when loadCommands is set). */
|
|
495
517
|
commands: Command[];
|
|
496
518
|
onSelect: (command: Command) => void;
|
|
519
|
+
/** Async source; called with the current query (debounced). */
|
|
520
|
+
loadCommands?: (query: string) => Promise<Command[]>;
|
|
521
|
+
/** Debounce for loadCommands, in ms. Default 200. */
|
|
522
|
+
debounceMs?: number;
|
|
523
|
+
/** Custom row renderer (icons, type badges, metadata). */
|
|
524
|
+
renderCommand?: (command: Command, state: {
|
|
525
|
+
active: boolean;
|
|
526
|
+
}) => React.ReactNode;
|
|
527
|
+
/** Shown while async commands load. */
|
|
528
|
+
loadingText?: string;
|
|
497
529
|
placeholder?: string;
|
|
498
530
|
};
|
|
499
531
|
/**
|
|
@@ -501,7 +533,7 @@ type CommandPaletteProps = {
|
|
|
501
533
|
* keyboard navigation, lexical filtering over label/keywords, and
|
|
502
534
|
* Escape-to-close. No focus leaves the input while navigating.
|
|
503
535
|
*/
|
|
504
|
-
declare function CommandPalette({ open, onOpenChange, commands, onSelect, placeholder, }: CommandPaletteProps): React.JSX.Element | null;
|
|
536
|
+
declare function CommandPalette({ open, onOpenChange, commands, onSelect, loadCommands, debounceMs, renderCommand, loadingText, placeholder, }: CommandPaletteProps): React.JSX.Element | null;
|
|
505
537
|
|
|
506
538
|
/**
|
|
507
539
|
* Structural types mirroring the parts of the Vercel AI SDK's chat state the
|
package/dist/index.js
CHANGED
|
@@ -377,11 +377,80 @@ function useIsDark() {
|
|
|
377
377
|
}, []);
|
|
378
378
|
return dark;
|
|
379
379
|
}
|
|
380
|
+
var LIGHT_CODE_THEME = {
|
|
381
|
+
plain: { color: "#1f2328", backgroundColor: "transparent" },
|
|
382
|
+
styles: [
|
|
383
|
+
{ types: ["comment", "prolog", "doctype", "cdata"], style: { color: "#57606a" } },
|
|
384
|
+
{ types: ["punctuation", "operator"], style: { color: "#24292f" } },
|
|
385
|
+
{ types: ["namespace"], style: { color: "#6f42c1" } },
|
|
386
|
+
{ types: ["tag", "deleted", "keyword", "atrule", "important"], style: { color: "#b31d28" } },
|
|
387
|
+
{ types: ["attr-name", "variable"], style: { color: "#953800" } },
|
|
388
|
+
{ types: ["string", "char", "attr-value", "inserted", "regex"], style: { color: "#0a5c2f" } },
|
|
389
|
+
{
|
|
390
|
+
types: [
|
|
391
|
+
"function",
|
|
392
|
+
"class-name",
|
|
393
|
+
"number",
|
|
394
|
+
"boolean",
|
|
395
|
+
"constant",
|
|
396
|
+
"symbol",
|
|
397
|
+
"property",
|
|
398
|
+
"selector",
|
|
399
|
+
"builtin",
|
|
400
|
+
"entity",
|
|
401
|
+
"url"
|
|
402
|
+
],
|
|
403
|
+
style: { color: "#0550ae" }
|
|
404
|
+
}
|
|
405
|
+
]
|
|
406
|
+
};
|
|
407
|
+
var DARK_CODE_THEME = {
|
|
408
|
+
plain: { color: "#e6edf3", backgroundColor: "transparent" },
|
|
409
|
+
styles: [
|
|
410
|
+
{ types: ["comment", "prolog", "doctype", "cdata"], style: { color: "#8b949e" } },
|
|
411
|
+
{ types: ["punctuation", "operator"], style: { color: "#c9d1d9" } },
|
|
412
|
+
{ types: ["namespace"], style: { color: "#d2a8ff" } },
|
|
413
|
+
{ types: ["tag", "deleted", "keyword", "atrule", "important"], style: { color: "#ff7b72" } },
|
|
414
|
+
{ types: ["attr-name", "variable"], style: { color: "#ffa657" } },
|
|
415
|
+
{ types: ["string", "char", "attr-value", "inserted", "regex"], style: { color: "#7ee787" } },
|
|
416
|
+
{
|
|
417
|
+
types: [
|
|
418
|
+
"function",
|
|
419
|
+
"class-name",
|
|
420
|
+
"number",
|
|
421
|
+
"boolean",
|
|
422
|
+
"constant",
|
|
423
|
+
"symbol",
|
|
424
|
+
"property",
|
|
425
|
+
"selector",
|
|
426
|
+
"builtin",
|
|
427
|
+
"entity",
|
|
428
|
+
"url"
|
|
429
|
+
],
|
|
430
|
+
style: { color: "#79c0ff" }
|
|
431
|
+
}
|
|
432
|
+
]
|
|
433
|
+
};
|
|
380
434
|
var CodeBlock = React5.forwardRef(
|
|
381
435
|
({ code, language = "tsx", showCopyButton = true, className, ...props }, ref) => {
|
|
382
436
|
const [copied, setCopied] = React5.useState(false);
|
|
383
437
|
const isDark = useIsDark();
|
|
384
438
|
const trimmedCode = code.replace(/\n$/, "");
|
|
439
|
+
const preRef = React5.useRef(null);
|
|
440
|
+
const [scrollable, setScrollable] = React5.useState(false);
|
|
441
|
+
React5.useEffect(() => {
|
|
442
|
+
const element = preRef.current;
|
|
443
|
+
if (!element) return;
|
|
444
|
+
const update = () => setScrollable(element.scrollWidth > element.clientWidth + 1);
|
|
445
|
+
update();
|
|
446
|
+
if (typeof ResizeObserver === "undefined") {
|
|
447
|
+
window.addEventListener("resize", update);
|
|
448
|
+
return () => window.removeEventListener("resize", update);
|
|
449
|
+
}
|
|
450
|
+
const observer = new ResizeObserver(update);
|
|
451
|
+
observer.observe(element);
|
|
452
|
+
return () => observer.disconnect();
|
|
453
|
+
}, [trimmedCode, language]);
|
|
385
454
|
const handleCopy = async () => {
|
|
386
455
|
try {
|
|
387
456
|
await navigator.clipboard.writeText(trimmedCode);
|
|
@@ -395,8 +464,8 @@ var CodeBlock = React5.forwardRef(
|
|
|
395
464
|
{
|
|
396
465
|
ref,
|
|
397
466
|
className: (0, import_core7.cn)(
|
|
398
|
-
// bg-background (not muted):
|
|
399
|
-
// surface
|
|
467
|
+
// bg-background (not muted): the light syntax palette is tuned for
|
|
468
|
+
// a white surface; on gray the token contrast drops below AA.
|
|
400
469
|
"relative group rounded-md border border-border bg-background overflow-hidden",
|
|
401
470
|
className
|
|
402
471
|
),
|
|
@@ -415,10 +484,13 @@ var CodeBlock = React5.forwardRef(
|
|
|
415
484
|
}
|
|
416
485
|
)
|
|
417
486
|
] }),
|
|
418
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_prism_react_renderer.Highlight, { theme: isDark ?
|
|
487
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_prism_react_renderer.Highlight, { theme: isDark ? DARK_CODE_THEME : LIGHT_CODE_THEME, code: trimmedCode, language, children: ({ style, tokens, getLineProps, getTokenProps }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
419
488
|
"pre",
|
|
420
489
|
{
|
|
421
|
-
|
|
490
|
+
ref: preRef,
|
|
491
|
+
tabIndex: scrollable ? 0 : void 0,
|
|
492
|
+
"aria-label": scrollable ? `${language} code, scrollable` : void 0,
|
|
493
|
+
className: "overflow-x-auto p-4 text-xs leading-relaxed m-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
422
494
|
style: { ...style, background: "transparent" },
|
|
423
495
|
children: tokens.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ...getLineProps({ line }), children: line.map((token, key) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { ...getTokenProps({ token }) }, key)) }, i))
|
|
424
496
|
}
|
|
@@ -515,7 +587,7 @@ var import_core9 = require("@slipstream-ui/core");
|
|
|
515
587
|
var import_core10 = require("@slipstream-ui/core");
|
|
516
588
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
517
589
|
var statusChipClasses = {
|
|
518
|
-
pending: "bg-warning/10 text-warning border-warning/20",
|
|
590
|
+
pending: "bg-warning/10 text-warning-ink border-warning/20",
|
|
519
591
|
approved: "bg-success/10 text-success border-success/20",
|
|
520
592
|
rejected: "bg-destructive/10 text-destructive border-destructive/20"
|
|
521
593
|
};
|
|
@@ -815,62 +887,71 @@ var Conversation = React10.forwardRef(
|
|
|
815
887
|
};
|
|
816
888
|
const isEmpty = messages.length === 0 && !isLoading;
|
|
817
889
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref, className: (0, import_core13.cn)("relative h-full w-full", className), ...props, children: [
|
|
818
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
children:
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
890
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
891
|
+
"div",
|
|
892
|
+
{
|
|
893
|
+
ref: scrollRef,
|
|
894
|
+
tabIndex: 0,
|
|
895
|
+
"aria-label": "Conversation transcript",
|
|
896
|
+
className: "flex flex-col gap-4 p-4 overflow-y-auto h-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
897
|
+
children: [
|
|
898
|
+
(hasMoreHistory || isLoadingMore) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
899
|
+
"button",
|
|
900
|
+
{
|
|
901
|
+
type: "button",
|
|
902
|
+
onClick: handleLoadMore,
|
|
903
|
+
disabled: isLoadingMore,
|
|
904
|
+
className: "mx-auto rounded-full border border-border bg-background px-3 py-1 text-xs text-muted-foreground hover:text-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50",
|
|
905
|
+
children: isLoadingMore ? "Loading\u2026" : "Load earlier messages"
|
|
906
|
+
}
|
|
907
|
+
),
|
|
908
|
+
isEmpty ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 text-center py-16", children: [
|
|
909
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { className: "text-lg font-semibold", children: welcomeTitle }),
|
|
910
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm text-muted-foreground max-w-sm", children: welcomeDescription }),
|
|
911
|
+
welcomeSuggestions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-2 flex flex-col gap-2 w-full max-w-sm", children: welcomeSuggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
912
|
+
"button",
|
|
913
|
+
{
|
|
914
|
+
type: "button",
|
|
915
|
+
onClick: () => onWelcomeSelect?.(suggestion),
|
|
916
|
+
className: "rounded-md border border-border bg-background px-4 py-2.5 text-sm text-left text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
917
|
+
children: suggestion
|
|
918
|
+
},
|
|
919
|
+
suggestion
|
|
920
|
+
)) })
|
|
921
|
+
] }) : messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
922
|
+
MemoizedMessage,
|
|
923
|
+
{
|
|
924
|
+
message,
|
|
925
|
+
showAvatar: showAvatars,
|
|
926
|
+
avatarSrc: message.role === "user" ? userAvatarSrc : assistantAvatarSrc,
|
|
927
|
+
avatarFallback: message.role === "user" ? userAvatarFallback : assistantAvatarFallback,
|
|
928
|
+
renderContent,
|
|
929
|
+
isStreaming: message.id === streamingMessageId,
|
|
930
|
+
error: messageErrors?.[message.id],
|
|
931
|
+
onRetry: onRetryMessage && messageErrors?.[message.id] ? () => onRetryMessage(message) : void 0
|
|
932
|
+
},
|
|
933
|
+
message.id
|
|
934
|
+
)),
|
|
935
|
+
isLoading && !isEmpty && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
936
|
+
MemoizedMessage,
|
|
937
|
+
{
|
|
938
|
+
message: {
|
|
939
|
+
id: "__loading__",
|
|
940
|
+
role: "assistant",
|
|
941
|
+
content: loadingMessage
|
|
942
|
+
},
|
|
943
|
+
showAvatar: showAvatars,
|
|
944
|
+
avatarSrc: assistantAvatarSrc,
|
|
945
|
+
avatarFallback: assistantAvatarFallback,
|
|
946
|
+
className: "bg-muted/50",
|
|
947
|
+
renderContent: (content) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-muted-foreground animate-pulse motion-reduce:animate-none", children: content })
|
|
948
|
+
}
|
|
949
|
+
),
|
|
950
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "aria-live": "polite", className: "sr-only", children: announcement }),
|
|
951
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: messagesEndRef })
|
|
952
|
+
]
|
|
953
|
+
}
|
|
954
|
+
),
|
|
874
955
|
showDownload && messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
875
956
|
"button",
|
|
876
957
|
{
|
|
@@ -1281,17 +1362,17 @@ var React12 = __toESM(require("react"));
|
|
|
1281
1362
|
var import_core16 = require("@slipstream-ui/core");
|
|
1282
1363
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1283
1364
|
var Reasoning = React12.forwardRef(
|
|
1284
|
-
({ steps, className, collapsible = true, defaultExpanded = false, duration, isStreaming = false, ...props }, ref) => {
|
|
1365
|
+
({ steps, className, collapsible = true, defaultExpanded = false, duration, isStreaming = false, labels, ...props }, ref) => {
|
|
1285
1366
|
const [isExpanded, setIsExpanded] = React12.useState(defaultExpanded);
|
|
1286
1367
|
const contentId = React12.useId();
|
|
1287
1368
|
if (steps.length === 0) {
|
|
1288
1369
|
return null;
|
|
1289
1370
|
}
|
|
1290
1371
|
const headerText = [
|
|
1291
|
-
"Reasoning",
|
|
1292
|
-
`(${steps.length} ${steps.length === 1 ? "step" : "steps"})`,
|
|
1372
|
+
labels?.title ?? "Reasoning",
|
|
1373
|
+
labels?.count ? labels.count(steps.length) : `(${steps.length} ${steps.length === 1 ? "step" : "steps"})`,
|
|
1293
1374
|
typeof duration === "number" ? `\xB7 ${duration}s` : duration ? `\xB7 ${duration}` : "",
|
|
1294
|
-
isStreaming ?
|
|
1375
|
+
isStreaming ? `\xB7 ${labels?.thinking ?? "thinking\u2026"}` : ""
|
|
1295
1376
|
].filter(Boolean).join(" ");
|
|
1296
1377
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { ref, className: (0, import_core16.cn)("border-l-2 border-muted-foreground/30 pl-4", className), ...props, children: [
|
|
1297
1378
|
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
@@ -1302,7 +1383,7 @@ var Reasoning = React12.forwardRef(
|
|
|
1302
1383
|
"aria-expanded": isExpanded,
|
|
1303
1384
|
"aria-controls": contentId,
|
|
1304
1385
|
children: [
|
|
1305
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: (0, import_core16.cn)("transition-transform", isExpanded ? "rotate-90" : ""), children: "
|
|
1386
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: (0, import_core16.cn)("transition-transform", isExpanded ? "rotate-90" : ""), children: "?" }),
|
|
1306
1387
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: headerText }),
|
|
1307
1388
|
isStreaming && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "flex gap-0.5", "aria-hidden": "true", children: [0, 150, 300].map((delay) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1308
1389
|
"span",
|
|
@@ -1318,10 +1399,7 @@ var Reasoning = React12.forwardRef(
|
|
|
1318
1399
|
(isExpanded || !collapsible) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { id: contentId, className: "mt-3 space-y-3", children: steps.map((step, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex gap-3", children: [
|
|
1319
1400
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "w-3 h-3 rounded-full bg-primary/20 border-2 border-primary flex-shrink-0 mt-1" }),
|
|
1320
1401
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "text-sm flex-1", children: [
|
|
1321
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.
|
|
1322
|
-
"Step ",
|
|
1323
|
-
index + 1
|
|
1324
|
-
] }),
|
|
1402
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "font-medium text-foreground mb-1", children: labels?.step?.(index + 1) ?? `Step ${index + 1}` }),
|
|
1325
1403
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "text-muted-foreground", children: step.content }),
|
|
1326
1404
|
step.timestamp && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "text-xs text-muted-foreground mt-1", children: new Date(step.timestamp).toLocaleTimeString() })
|
|
1327
1405
|
] })
|
|
@@ -1336,19 +1414,19 @@ var React13 = __toESM(require("react"));
|
|
|
1336
1414
|
var import_core17 = require("@slipstream-ui/core");
|
|
1337
1415
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1338
1416
|
var statusChipClasses2 = {
|
|
1339
|
-
pending: "bg-warning/10 text-warning border-warning/20",
|
|
1340
|
-
running: "bg-info/10 text-info border-info/20",
|
|
1417
|
+
pending: "bg-warning/10 text-warning-ink border-warning/20",
|
|
1418
|
+
running: "bg-info/10 text-info-ink border-info/20",
|
|
1341
1419
|
completed: "bg-success/10 text-success border-success/20",
|
|
1342
1420
|
failed: "bg-destructive/10 text-destructive border-destructive/20"
|
|
1343
1421
|
};
|
|
1344
|
-
var
|
|
1422
|
+
var defaultStatusLabels = {
|
|
1345
1423
|
pending: "Pending",
|
|
1346
1424
|
running: "Running",
|
|
1347
1425
|
completed: "Completed",
|
|
1348
1426
|
failed: "Failed"
|
|
1349
1427
|
};
|
|
1350
1428
|
var ToolCall = React13.forwardRef(
|
|
1351
|
-
({ toolCall, className, showResult = true, ...props }, ref) => {
|
|
1429
|
+
({ toolCall, className, showResult = true, labels, ...props }, ref) => {
|
|
1352
1430
|
const serializedArguments = React13.useMemo(
|
|
1353
1431
|
() => JSON.stringify(toolCall.arguments, null, 2),
|
|
1354
1432
|
[toolCall.arguments]
|
|
@@ -1357,6 +1435,12 @@ var ToolCall = React13.forwardRef(
|
|
|
1357
1435
|
if (toolCall.result === void 0) return void 0;
|
|
1358
1436
|
return typeof toolCall.result === "string" ? toolCall.result : JSON.stringify(toolCall.result, null, 2);
|
|
1359
1437
|
}, [toolCall.result]);
|
|
1438
|
+
const statusLabels = {
|
|
1439
|
+
pending: labels?.pending ?? defaultStatusLabels.pending,
|
|
1440
|
+
running: labels?.running ?? defaultStatusLabels.running,
|
|
1441
|
+
completed: labels?.completed ?? defaultStatusLabels.completed,
|
|
1442
|
+
failed: labels?.failed ?? defaultStatusLabels.failed
|
|
1443
|
+
};
|
|
1360
1444
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1361
1445
|
"div",
|
|
1362
1446
|
{
|
|
@@ -1385,15 +1469,15 @@ var ToolCall = React13.forwardRef(
|
|
|
1385
1469
|
] }),
|
|
1386
1470
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-2", children: [
|
|
1387
1471
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
1388
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-xs font-medium text-muted-foreground mb-1", children: "Arguments" }),
|
|
1472
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-xs font-medium text-muted-foreground mb-1", children: labels?.arguments ?? "Arguments" }),
|
|
1389
1473
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("pre", { className: "text-xs bg-muted p-2 rounded overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("code", { children: serializedArguments }) })
|
|
1390
1474
|
] }),
|
|
1391
1475
|
showResult && serializedResult !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
1392
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-xs font-medium text-muted-foreground mb-1", children: "Result" }),
|
|
1476
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-xs font-medium text-muted-foreground mb-1", children: labels?.result ?? "Result" }),
|
|
1393
1477
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("pre", { className: "text-xs bg-muted p-2 rounded overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("code", { children: serializedResult }) })
|
|
1394
1478
|
] }),
|
|
1395
1479
|
toolCall.status === "failed" && toolCall.error && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { role: "alert", children: [
|
|
1396
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-xs font-medium text-destructive mb-1", children: "Error" }),
|
|
1480
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-xs font-medium text-destructive mb-1", children: labels?.error ?? "Error" }),
|
|
1397
1481
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("pre", { className: "text-xs bg-destructive/10 text-destructive p-2 rounded overflow-x-auto whitespace-pre-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("code", { children: toolCall.error }) })
|
|
1398
1482
|
] })
|
|
1399
1483
|
] })
|
|
@@ -1559,21 +1643,46 @@ function CommandPalette({
|
|
|
1559
1643
|
onOpenChange,
|
|
1560
1644
|
commands,
|
|
1561
1645
|
onSelect,
|
|
1562
|
-
|
|
1646
|
+
loadCommands,
|
|
1647
|
+
debounceMs = 200,
|
|
1648
|
+
renderCommand,
|
|
1649
|
+
loadingText = "Searching\u2026",
|
|
1650
|
+
placeholder = "Type a command."
|
|
1563
1651
|
}) {
|
|
1564
1652
|
const [query, setQuery] = React19.useState("");
|
|
1565
1653
|
const [activeIndex, setActiveIndex] = React19.useState(0);
|
|
1654
|
+
const [asyncCommands, setAsyncCommands] = React19.useState([]);
|
|
1655
|
+
const [loading, setLoading] = React19.useState(false);
|
|
1656
|
+
const requestId = React19.useRef(0);
|
|
1657
|
+
const asyncSignature = loadCommands ? String(loadCommands.length) : "";
|
|
1566
1658
|
const inputRef = React19.useRef(null);
|
|
1567
1659
|
const listboxId = React19.useId();
|
|
1568
1660
|
const optionId = (index) => `${listboxId}-option-${index}`;
|
|
1661
|
+
React19.useEffect(() => {
|
|
1662
|
+
if (!open || !loadCommands) return;
|
|
1663
|
+
const id = ++requestId.current;
|
|
1664
|
+
setLoading(true);
|
|
1665
|
+
const timer = setTimeout(async () => {
|
|
1666
|
+
try {
|
|
1667
|
+
const result = await loadCommands(query);
|
|
1668
|
+
if (requestId.current === id) setAsyncCommands(result);
|
|
1669
|
+
} catch {
|
|
1670
|
+
if (requestId.current === id) setAsyncCommands([]);
|
|
1671
|
+
} finally {
|
|
1672
|
+
if (requestId.current === id) setLoading(false);
|
|
1673
|
+
}
|
|
1674
|
+
}, debounceMs);
|
|
1675
|
+
return () => clearTimeout(timer);
|
|
1676
|
+
}, [open, query, debounceMs, asyncSignature]);
|
|
1569
1677
|
const filtered = React19.useMemo(() => {
|
|
1678
|
+
if (loadCommands) return asyncCommands;
|
|
1570
1679
|
const terms = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
1571
1680
|
if (terms.length === 0) return commands;
|
|
1572
1681
|
return commands.filter((command) => {
|
|
1573
1682
|
const haystack = `${command.label} ${command.section ?? ""} ${(command.keywords ?? []).join(" ")}`.toLowerCase();
|
|
1574
1683
|
return terms.every((term) => haystack.includes(term));
|
|
1575
1684
|
});
|
|
1576
|
-
}, [commands, query]);
|
|
1685
|
+
}, [commands, query, asyncCommands, loadCommands]);
|
|
1577
1686
|
React19.useEffect(() => {
|
|
1578
1687
|
if (open) {
|
|
1579
1688
|
setQuery("");
|
|
@@ -1636,37 +1745,54 @@ function CommandPalette({
|
|
|
1636
1745
|
className: "w-full border-b border-border bg-transparent px-4 py-3 text-sm outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring placeholder:text-muted-foreground"
|
|
1637
1746
|
}
|
|
1638
1747
|
),
|
|
1639
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1748
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1749
|
+
"ul",
|
|
1750
|
+
{
|
|
1751
|
+
id: listboxId,
|
|
1752
|
+
role: "listbox",
|
|
1753
|
+
"aria-label": "Commands",
|
|
1754
|
+
"aria-busy": loading || void 0,
|
|
1755
|
+
className: "max-h-72 overflow-y-auto py-1",
|
|
1756
|
+
children: [
|
|
1757
|
+
loading && filtered.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("li", { role: "presentation", className: "px-4 py-3 text-sm text-muted-foreground", children: loadingText }),
|
|
1758
|
+
!loading && filtered.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("li", { role: "presentation", className: "px-4 py-3 text-sm text-muted-foreground", children: "No matching commands." }),
|
|
1759
|
+
filtered.map((command, index) => {
|
|
1760
|
+
const showSection = command.section && command.section !== lastSection;
|
|
1761
|
+
lastSection = command.section ?? lastSection;
|
|
1762
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(React19.Fragment, { children: [
|
|
1763
|
+
showSection && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("li", { role: "presentation", className: "px-4 pb-1 pt-3 text-xs font-medium uppercase text-muted-foreground", children: command.section }),
|
|
1764
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1765
|
+
"li",
|
|
1766
|
+
{
|
|
1767
|
+
id: optionId(index),
|
|
1768
|
+
role: "option",
|
|
1769
|
+
"aria-selected": index === activeIndex,
|
|
1770
|
+
onMouseEnter: () => setActiveIndex(index),
|
|
1771
|
+
onClick: () => {
|
|
1772
|
+
onSelect(command);
|
|
1773
|
+
onOpenChange(false);
|
|
1774
|
+
},
|
|
1775
|
+
className: (0, import_core23.cn)(
|
|
1776
|
+
"flex cursor-pointer items-center justify-between px-4 py-2 text-sm",
|
|
1777
|
+
index === activeIndex ? "bg-primary/10 text-foreground" : "text-muted-foreground"
|
|
1778
|
+
),
|
|
1779
|
+
children: renderCommand ? renderCommand(command, { active: index === activeIndex }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
1780
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1781
|
+
command.icon && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0 [&_svg]:size-4", children: command.icon }),
|
|
1782
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "min-w-0", children: [
|
|
1783
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "block truncate", children: command.label }),
|
|
1784
|
+
command.description && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "block text-xs text-muted-foreground", children: command.description })
|
|
1785
|
+
] })
|
|
1786
|
+
] }),
|
|
1787
|
+
command.shortcut && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-mono text-xs", children: command.shortcut })
|
|
1788
|
+
] })
|
|
1789
|
+
}
|
|
1790
|
+
)
|
|
1791
|
+
] }, command.id);
|
|
1792
|
+
})
|
|
1793
|
+
]
|
|
1794
|
+
}
|
|
1795
|
+
)
|
|
1670
1796
|
] })
|
|
1671
1797
|
}
|
|
1672
1798
|
);
|