@slipstream-ui/ai 0.4.0 → 0.6.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 +51 -4
- package/dist/index.d.ts +51 -4
- package/dist/index.js +244 -113
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +246 -115
- package/dist/index.mjs.map +1 -1
- package/dist/manifests/attachment.manifest.json +37 -8
- package/dist/manifests/branch.manifest.json +3 -1
- package/dist/manifests/chain-thought.manifest.json +1 -1
- package/dist/manifests/code-block.manifest.json +3 -1
- package/dist/manifests/command-palette.manifest.json +59 -4
- package/dist/manifests/confirmation.manifest.json +3 -1
- package/dist/manifests/conversation.manifest.json +1 -1
- package/dist/manifests/inline-citation.manifest.json +3 -1
- package/dist/manifests/message-actions.manifest.json +61 -10
- package/dist/manifests/message.manifest.json +13 -1
- package/dist/manifests/prompt-input.manifest.json +2 -2
- package/dist/manifests/reasoning.manifest.json +19 -1
- package/dist/manifests/response.manifest.json +3 -1
- package/dist/manifests/source.manifest.json +2 -2
- package/dist/manifests/streaming-indicator.manifest.json +1 -1
- package/dist/manifests/suggestions.manifest.json +2 -2
- package/dist/manifests/tool-call.manifest.json +7 -1
- package/package.json +10 -10
- package/src/components/code-block/CodeBlock.tsx +91 -5
- package/src/components/command-palette/CommandPalette.test.tsx +42 -0
- package/src/components/command-palette/CommandPalette.tsx +82 -8
- package/src/components/confirmation/Confirmation.tsx +1 -1
- package/src/components/conversation/Conversation.tsx +6 -1
- package/src/components/message/Message.test.tsx +15 -0
- package/src/components/message/Message.tsx +9 -1
- package/src/components/reasoning/Reasoning.test.tsx +15 -0
- package/src/components/reasoning/Reasoning.tsx +20 -7
- package/src/components/tool-call/ToolCall.tsx +24 -8
- package/src/manifests/attachment.manifest.json +37 -8
- package/src/manifests/branch.manifest.json +3 -1
- package/src/manifests/chain-thought.manifest.json +1 -1
- package/src/manifests/code-block.manifest.json +3 -1
- package/src/manifests/command-palette.manifest.json +59 -4
- package/src/manifests/confirmation.manifest.json +3 -1
- package/src/manifests/conversation.manifest.json +1 -1
- package/src/manifests/inline-citation.manifest.json +3 -1
- package/src/manifests/message-actions.manifest.json +61 -10
- package/src/manifests/message.manifest.json +13 -1
- package/src/manifests/prompt-input.manifest.json +2 -2
- package/src/manifests/reasoning.manifest.json +19 -1
- package/src/manifests/response.manifest.json +3 -1
- package/src/manifests/source.manifest.json +2 -2
- package/src/manifests/streaming-indicator.manifest.json +1 -1
- package/src/manifests/suggestions.manifest.json +2 -2
- package/src/manifests/tool-call.manifest.json +7 -1
package/dist/index.js
CHANGED
|
@@ -85,6 +85,8 @@ var Message = React.forwardRef(
|
|
|
85
85
|
avatarFallback,
|
|
86
86
|
userLabel = "You",
|
|
87
87
|
assistantLabel = "Assistant",
|
|
88
|
+
formatTime,
|
|
89
|
+
locale,
|
|
88
90
|
renderContent,
|
|
89
91
|
isStreaming = false,
|
|
90
92
|
error,
|
|
@@ -138,7 +140,7 @@ var Message = React.forwardRef(
|
|
|
138
140
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
139
141
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 mb-1", children: [
|
|
140
142
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-medium", children: displayLabel }),
|
|
141
|
-
message.timestamp && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-muted-foreground", children: new Date(message.timestamp).toLocaleTimeString() })
|
|
143
|
+
message.timestamp && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-muted-foreground", children: formatTime ? formatTime(new Date(message.timestamp)) : new Date(message.timestamp).toLocaleTimeString(locale) })
|
|
142
144
|
] }),
|
|
143
145
|
error ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { role: "alert", className: "text-sm", children: [
|
|
144
146
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-destructive mb-2", children: error }),
|
|
@@ -377,11 +379,80 @@ function useIsDark() {
|
|
|
377
379
|
}, []);
|
|
378
380
|
return dark;
|
|
379
381
|
}
|
|
382
|
+
var LIGHT_CODE_THEME = {
|
|
383
|
+
plain: { color: "#1f2328", backgroundColor: "transparent" },
|
|
384
|
+
styles: [
|
|
385
|
+
{ types: ["comment", "prolog", "doctype", "cdata"], style: { color: "#57606a" } },
|
|
386
|
+
{ types: ["punctuation", "operator"], style: { color: "#24292f" } },
|
|
387
|
+
{ types: ["namespace"], style: { color: "#6f42c1" } },
|
|
388
|
+
{ types: ["tag", "deleted", "keyword", "atrule", "important"], style: { color: "#b31d28" } },
|
|
389
|
+
{ types: ["attr-name", "variable"], style: { color: "#953800" } },
|
|
390
|
+
{ types: ["string", "char", "attr-value", "inserted", "regex"], style: { color: "#0a5c2f" } },
|
|
391
|
+
{
|
|
392
|
+
types: [
|
|
393
|
+
"function",
|
|
394
|
+
"class-name",
|
|
395
|
+
"number",
|
|
396
|
+
"boolean",
|
|
397
|
+
"constant",
|
|
398
|
+
"symbol",
|
|
399
|
+
"property",
|
|
400
|
+
"selector",
|
|
401
|
+
"builtin",
|
|
402
|
+
"entity",
|
|
403
|
+
"url"
|
|
404
|
+
],
|
|
405
|
+
style: { color: "#0550ae" }
|
|
406
|
+
}
|
|
407
|
+
]
|
|
408
|
+
};
|
|
409
|
+
var DARK_CODE_THEME = {
|
|
410
|
+
plain: { color: "#e6edf3", backgroundColor: "transparent" },
|
|
411
|
+
styles: [
|
|
412
|
+
{ types: ["comment", "prolog", "doctype", "cdata"], style: { color: "#8b949e" } },
|
|
413
|
+
{ types: ["punctuation", "operator"], style: { color: "#c9d1d9" } },
|
|
414
|
+
{ types: ["namespace"], style: { color: "#d2a8ff" } },
|
|
415
|
+
{ types: ["tag", "deleted", "keyword", "atrule", "important"], style: { color: "#ff7b72" } },
|
|
416
|
+
{ types: ["attr-name", "variable"], style: { color: "#ffa657" } },
|
|
417
|
+
{ types: ["string", "char", "attr-value", "inserted", "regex"], style: { color: "#7ee787" } },
|
|
418
|
+
{
|
|
419
|
+
types: [
|
|
420
|
+
"function",
|
|
421
|
+
"class-name",
|
|
422
|
+
"number",
|
|
423
|
+
"boolean",
|
|
424
|
+
"constant",
|
|
425
|
+
"symbol",
|
|
426
|
+
"property",
|
|
427
|
+
"selector",
|
|
428
|
+
"builtin",
|
|
429
|
+
"entity",
|
|
430
|
+
"url"
|
|
431
|
+
],
|
|
432
|
+
style: { color: "#79c0ff" }
|
|
433
|
+
}
|
|
434
|
+
]
|
|
435
|
+
};
|
|
380
436
|
var CodeBlock = React5.forwardRef(
|
|
381
437
|
({ code, language = "tsx", showCopyButton = true, className, ...props }, ref) => {
|
|
382
438
|
const [copied, setCopied] = React5.useState(false);
|
|
383
439
|
const isDark = useIsDark();
|
|
384
440
|
const trimmedCode = code.replace(/\n$/, "");
|
|
441
|
+
const preRef = React5.useRef(null);
|
|
442
|
+
const [scrollable, setScrollable] = React5.useState(false);
|
|
443
|
+
React5.useEffect(() => {
|
|
444
|
+
const element = preRef.current;
|
|
445
|
+
if (!element) return;
|
|
446
|
+
const update = () => setScrollable(element.scrollWidth > element.clientWidth + 1);
|
|
447
|
+
update();
|
|
448
|
+
if (typeof ResizeObserver === "undefined") {
|
|
449
|
+
window.addEventListener("resize", update);
|
|
450
|
+
return () => window.removeEventListener("resize", update);
|
|
451
|
+
}
|
|
452
|
+
const observer = new ResizeObserver(update);
|
|
453
|
+
observer.observe(element);
|
|
454
|
+
return () => observer.disconnect();
|
|
455
|
+
}, [trimmedCode, language]);
|
|
385
456
|
const handleCopy = async () => {
|
|
386
457
|
try {
|
|
387
458
|
await navigator.clipboard.writeText(trimmedCode);
|
|
@@ -395,8 +466,8 @@ var CodeBlock = React5.forwardRef(
|
|
|
395
466
|
{
|
|
396
467
|
ref,
|
|
397
468
|
className: (0, import_core7.cn)(
|
|
398
|
-
// bg-background (not muted):
|
|
399
|
-
// surface
|
|
469
|
+
// bg-background (not muted): the light syntax palette is tuned for
|
|
470
|
+
// a white surface; on gray the token contrast drops below AA.
|
|
400
471
|
"relative group rounded-md border border-border bg-background overflow-hidden",
|
|
401
472
|
className
|
|
402
473
|
),
|
|
@@ -415,10 +486,13 @@ var CodeBlock = React5.forwardRef(
|
|
|
415
486
|
}
|
|
416
487
|
)
|
|
417
488
|
] }),
|
|
418
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_prism_react_renderer.Highlight, { theme: isDark ?
|
|
489
|
+
/* @__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
490
|
"pre",
|
|
420
491
|
{
|
|
421
|
-
|
|
492
|
+
ref: preRef,
|
|
493
|
+
tabIndex: scrollable ? 0 : void 0,
|
|
494
|
+
"aria-label": scrollable ? `${language} code, scrollable` : void 0,
|
|
495
|
+
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
496
|
style: { ...style, background: "transparent" },
|
|
423
497
|
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
498
|
}
|
|
@@ -515,7 +589,7 @@ var import_core9 = require("@slipstream-ui/core");
|
|
|
515
589
|
var import_core10 = require("@slipstream-ui/core");
|
|
516
590
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
517
591
|
var statusChipClasses = {
|
|
518
|
-
pending: "bg-warning/10 text-warning border-warning/20",
|
|
592
|
+
pending: "bg-warning/10 text-warning-ink border-warning/20",
|
|
519
593
|
approved: "bg-success/10 text-success border-success/20",
|
|
520
594
|
rejected: "bg-destructive/10 text-destructive border-destructive/20"
|
|
521
595
|
};
|
|
@@ -815,62 +889,71 @@ var Conversation = React10.forwardRef(
|
|
|
815
889
|
};
|
|
816
890
|
const isEmpty = messages.length === 0 && !isLoading;
|
|
817
891
|
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
|
-
|
|
892
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
893
|
+
"div",
|
|
894
|
+
{
|
|
895
|
+
ref: scrollRef,
|
|
896
|
+
tabIndex: 0,
|
|
897
|
+
"aria-label": "Conversation transcript",
|
|
898
|
+
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",
|
|
899
|
+
children: [
|
|
900
|
+
(hasMoreHistory || isLoadingMore) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
901
|
+
"button",
|
|
902
|
+
{
|
|
903
|
+
type: "button",
|
|
904
|
+
onClick: handleLoadMore,
|
|
905
|
+
disabled: isLoadingMore,
|
|
906
|
+
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",
|
|
907
|
+
children: isLoadingMore ? "Loading\u2026" : "Load earlier messages"
|
|
908
|
+
}
|
|
909
|
+
),
|
|
910
|
+
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: [
|
|
911
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { className: "text-lg font-semibold", children: welcomeTitle }),
|
|
912
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm text-muted-foreground max-w-sm", children: welcomeDescription }),
|
|
913
|
+
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)(
|
|
914
|
+
"button",
|
|
915
|
+
{
|
|
916
|
+
type: "button",
|
|
917
|
+
onClick: () => onWelcomeSelect?.(suggestion),
|
|
918
|
+
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",
|
|
919
|
+
children: suggestion
|
|
920
|
+
},
|
|
921
|
+
suggestion
|
|
922
|
+
)) })
|
|
923
|
+
] }) : messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
924
|
+
MemoizedMessage,
|
|
925
|
+
{
|
|
926
|
+
message,
|
|
927
|
+
showAvatar: showAvatars,
|
|
928
|
+
avatarSrc: message.role === "user" ? userAvatarSrc : assistantAvatarSrc,
|
|
929
|
+
avatarFallback: message.role === "user" ? userAvatarFallback : assistantAvatarFallback,
|
|
930
|
+
renderContent,
|
|
931
|
+
isStreaming: message.id === streamingMessageId,
|
|
932
|
+
error: messageErrors?.[message.id],
|
|
933
|
+
onRetry: onRetryMessage && messageErrors?.[message.id] ? () => onRetryMessage(message) : void 0
|
|
934
|
+
},
|
|
935
|
+
message.id
|
|
936
|
+
)),
|
|
937
|
+
isLoading && !isEmpty && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
938
|
+
MemoizedMessage,
|
|
939
|
+
{
|
|
940
|
+
message: {
|
|
941
|
+
id: "__loading__",
|
|
942
|
+
role: "assistant",
|
|
943
|
+
content: loadingMessage
|
|
944
|
+
},
|
|
945
|
+
showAvatar: showAvatars,
|
|
946
|
+
avatarSrc: assistantAvatarSrc,
|
|
947
|
+
avatarFallback: assistantAvatarFallback,
|
|
948
|
+
className: "bg-muted/50",
|
|
949
|
+
renderContent: (content) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-muted-foreground animate-pulse motion-reduce:animate-none", children: content })
|
|
950
|
+
}
|
|
951
|
+
),
|
|
952
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "aria-live": "polite", className: "sr-only", children: announcement }),
|
|
953
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: messagesEndRef })
|
|
954
|
+
]
|
|
955
|
+
}
|
|
956
|
+
),
|
|
874
957
|
showDownload && messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
875
958
|
"button",
|
|
876
959
|
{
|
|
@@ -1281,17 +1364,17 @@ var React12 = __toESM(require("react"));
|
|
|
1281
1364
|
var import_core16 = require("@slipstream-ui/core");
|
|
1282
1365
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1283
1366
|
var Reasoning = React12.forwardRef(
|
|
1284
|
-
({ steps, className, collapsible = true, defaultExpanded = false, duration, isStreaming = false, ...props }, ref) => {
|
|
1367
|
+
({ steps, className, collapsible = true, defaultExpanded = false, duration, isStreaming = false, labels, formatTime, locale, ...props }, ref) => {
|
|
1285
1368
|
const [isExpanded, setIsExpanded] = React12.useState(defaultExpanded);
|
|
1286
1369
|
const contentId = React12.useId();
|
|
1287
1370
|
if (steps.length === 0) {
|
|
1288
1371
|
return null;
|
|
1289
1372
|
}
|
|
1290
1373
|
const headerText = [
|
|
1291
|
-
"Reasoning",
|
|
1292
|
-
`(${steps.length} ${steps.length === 1 ? "step" : "steps"})`,
|
|
1374
|
+
labels?.title ?? "Reasoning",
|
|
1375
|
+
labels?.count ? labels.count(steps.length) : `(${steps.length} ${steps.length === 1 ? "step" : "steps"})`,
|
|
1293
1376
|
typeof duration === "number" ? `\xB7 ${duration}s` : duration ? `\xB7 ${duration}` : "",
|
|
1294
|
-
isStreaming ?
|
|
1377
|
+
isStreaming ? `\xB7 ${labels?.thinking ?? "thinking\u2026"}` : ""
|
|
1295
1378
|
].filter(Boolean).join(" ");
|
|
1296
1379
|
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
1380
|
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
@@ -1302,7 +1385,7 @@ var Reasoning = React12.forwardRef(
|
|
|
1302
1385
|
"aria-expanded": isExpanded,
|
|
1303
1386
|
"aria-controls": contentId,
|
|
1304
1387
|
children: [
|
|
1305
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: (0, import_core16.cn)("transition-transform", isExpanded ? "rotate-90" : ""), children: "
|
|
1388
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: (0, import_core16.cn)("transition-transform", isExpanded ? "rotate-90" : ""), children: "?" }),
|
|
1306
1389
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: headerText }),
|
|
1307
1390
|
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
1391
|
"span",
|
|
@@ -1318,12 +1401,9 @@ var Reasoning = React12.forwardRef(
|
|
|
1318
1401
|
(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
1402
|
/* @__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
1403
|
/* @__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
|
-
] }),
|
|
1404
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "font-medium text-foreground mb-1", children: labels?.step?.(index + 1) ?? `Step ${index + 1}` }),
|
|
1325
1405
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "text-muted-foreground", children: step.content }),
|
|
1326
|
-
step.timestamp && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "text-xs text-muted-foreground mt-1", children: new Date(step.timestamp).toLocaleTimeString() })
|
|
1406
|
+
step.timestamp && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "text-xs text-muted-foreground mt-1", children: formatTime ? formatTime(new Date(step.timestamp)) : new Date(step.timestamp).toLocaleTimeString(locale) })
|
|
1327
1407
|
] })
|
|
1328
1408
|
] }, step.id)) })
|
|
1329
1409
|
] });
|
|
@@ -1336,19 +1416,19 @@ var React13 = __toESM(require("react"));
|
|
|
1336
1416
|
var import_core17 = require("@slipstream-ui/core");
|
|
1337
1417
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1338
1418
|
var statusChipClasses2 = {
|
|
1339
|
-
pending: "bg-warning/10 text-warning border-warning/20",
|
|
1340
|
-
running: "bg-info/10 text-info border-info/20",
|
|
1419
|
+
pending: "bg-warning/10 text-warning-ink border-warning/20",
|
|
1420
|
+
running: "bg-info/10 text-info-ink border-info/20",
|
|
1341
1421
|
completed: "bg-success/10 text-success border-success/20",
|
|
1342
1422
|
failed: "bg-destructive/10 text-destructive border-destructive/20"
|
|
1343
1423
|
};
|
|
1344
|
-
var
|
|
1424
|
+
var defaultStatusLabels = {
|
|
1345
1425
|
pending: "Pending",
|
|
1346
1426
|
running: "Running",
|
|
1347
1427
|
completed: "Completed",
|
|
1348
1428
|
failed: "Failed"
|
|
1349
1429
|
};
|
|
1350
1430
|
var ToolCall = React13.forwardRef(
|
|
1351
|
-
({ toolCall, className, showResult = true, ...props }, ref) => {
|
|
1431
|
+
({ toolCall, className, showResult = true, labels, ...props }, ref) => {
|
|
1352
1432
|
const serializedArguments = React13.useMemo(
|
|
1353
1433
|
() => JSON.stringify(toolCall.arguments, null, 2),
|
|
1354
1434
|
[toolCall.arguments]
|
|
@@ -1357,6 +1437,12 @@ var ToolCall = React13.forwardRef(
|
|
|
1357
1437
|
if (toolCall.result === void 0) return void 0;
|
|
1358
1438
|
return typeof toolCall.result === "string" ? toolCall.result : JSON.stringify(toolCall.result, null, 2);
|
|
1359
1439
|
}, [toolCall.result]);
|
|
1440
|
+
const statusLabels = {
|
|
1441
|
+
pending: labels?.pending ?? defaultStatusLabels.pending,
|
|
1442
|
+
running: labels?.running ?? defaultStatusLabels.running,
|
|
1443
|
+
completed: labels?.completed ?? defaultStatusLabels.completed,
|
|
1444
|
+
failed: labels?.failed ?? defaultStatusLabels.failed
|
|
1445
|
+
};
|
|
1360
1446
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1361
1447
|
"div",
|
|
1362
1448
|
{
|
|
@@ -1385,15 +1471,15 @@ var ToolCall = React13.forwardRef(
|
|
|
1385
1471
|
] }),
|
|
1386
1472
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-2", children: [
|
|
1387
1473
|
/* @__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" }),
|
|
1474
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-xs font-medium text-muted-foreground mb-1", children: labels?.arguments ?? "Arguments" }),
|
|
1389
1475
|
/* @__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
1476
|
] }),
|
|
1391
1477
|
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" }),
|
|
1478
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-xs font-medium text-muted-foreground mb-1", children: labels?.result ?? "Result" }),
|
|
1393
1479
|
/* @__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
1480
|
] }),
|
|
1395
1481
|
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" }),
|
|
1482
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-xs font-medium text-destructive mb-1", children: labels?.error ?? "Error" }),
|
|
1397
1483
|
/* @__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
1484
|
] })
|
|
1399
1485
|
] })
|
|
@@ -1559,21 +1645,49 @@ function CommandPalette({
|
|
|
1559
1645
|
onOpenChange,
|
|
1560
1646
|
commands,
|
|
1561
1647
|
onSelect,
|
|
1562
|
-
|
|
1648
|
+
loadCommands,
|
|
1649
|
+
debounceMs = 200,
|
|
1650
|
+
renderCommand,
|
|
1651
|
+
loadingText = "Searching\u2026",
|
|
1652
|
+
placeholder = "Type a command.",
|
|
1653
|
+
dialogLabel = "Command palette",
|
|
1654
|
+
listLabel = "Commands",
|
|
1655
|
+
emptyText = "No matching commands."
|
|
1563
1656
|
}) {
|
|
1564
1657
|
const [query, setQuery] = React19.useState("");
|
|
1565
1658
|
const [activeIndex, setActiveIndex] = React19.useState(0);
|
|
1659
|
+
const [asyncCommands, setAsyncCommands] = React19.useState([]);
|
|
1660
|
+
const [loading, setLoading] = React19.useState(false);
|
|
1661
|
+
const requestId = React19.useRef(0);
|
|
1662
|
+
const asyncSignature = loadCommands ? String(loadCommands.length) : "";
|
|
1566
1663
|
const inputRef = React19.useRef(null);
|
|
1567
1664
|
const listboxId = React19.useId();
|
|
1568
1665
|
const optionId = (index) => `${listboxId}-option-${index}`;
|
|
1666
|
+
React19.useEffect(() => {
|
|
1667
|
+
if (!open || !loadCommands) return;
|
|
1668
|
+
const id = ++requestId.current;
|
|
1669
|
+
setLoading(true);
|
|
1670
|
+
const timer = setTimeout(async () => {
|
|
1671
|
+
try {
|
|
1672
|
+
const result = await loadCommands(query);
|
|
1673
|
+
if (requestId.current === id) setAsyncCommands(result);
|
|
1674
|
+
} catch {
|
|
1675
|
+
if (requestId.current === id) setAsyncCommands([]);
|
|
1676
|
+
} finally {
|
|
1677
|
+
if (requestId.current === id) setLoading(false);
|
|
1678
|
+
}
|
|
1679
|
+
}, debounceMs);
|
|
1680
|
+
return () => clearTimeout(timer);
|
|
1681
|
+
}, [open, query, debounceMs, asyncSignature]);
|
|
1569
1682
|
const filtered = React19.useMemo(() => {
|
|
1683
|
+
if (loadCommands) return asyncCommands;
|
|
1570
1684
|
const terms = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
1571
1685
|
if (terms.length === 0) return commands;
|
|
1572
1686
|
return commands.filter((command) => {
|
|
1573
1687
|
const haystack = `${command.label} ${command.section ?? ""} ${(command.keywords ?? []).join(" ")}`.toLowerCase();
|
|
1574
1688
|
return terms.every((term) => haystack.includes(term));
|
|
1575
1689
|
});
|
|
1576
|
-
}, [commands, query]);
|
|
1690
|
+
}, [commands, query, asyncCommands, loadCommands]);
|
|
1577
1691
|
React19.useEffect(() => {
|
|
1578
1692
|
if (open) {
|
|
1579
1693
|
setQuery("");
|
|
@@ -1625,7 +1739,7 @@ function CommandPalette({
|
|
|
1625
1739
|
"aria-controls": listboxId,
|
|
1626
1740
|
"aria-activedescendant": filtered.length > 0 ? optionId(activeIndex) : void 0,
|
|
1627
1741
|
"aria-autocomplete": "list",
|
|
1628
|
-
"aria-label":
|
|
1742
|
+
"aria-label": dialogLabel,
|
|
1629
1743
|
placeholder,
|
|
1630
1744
|
value: query,
|
|
1631
1745
|
onChange: (event) => {
|
|
@@ -1636,37 +1750,54 @@ function CommandPalette({
|
|
|
1636
1750
|
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
1751
|
}
|
|
1638
1752
|
),
|
|
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
|
-
|
|
1753
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1754
|
+
"ul",
|
|
1755
|
+
{
|
|
1756
|
+
id: listboxId,
|
|
1757
|
+
role: "listbox",
|
|
1758
|
+
"aria-label": listLabel,
|
|
1759
|
+
"aria-busy": loading || void 0,
|
|
1760
|
+
className: "max-h-72 overflow-y-auto py-1",
|
|
1761
|
+
children: [
|
|
1762
|
+
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 }),
|
|
1763
|
+
!loading && filtered.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("li", { role: "presentation", className: "px-4 py-3 text-sm text-muted-foreground", children: emptyText }),
|
|
1764
|
+
filtered.map((command, index) => {
|
|
1765
|
+
const showSection = command.section && command.section !== lastSection;
|
|
1766
|
+
lastSection = command.section ?? lastSection;
|
|
1767
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(React19.Fragment, { children: [
|
|
1768
|
+
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 }),
|
|
1769
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1770
|
+
"li",
|
|
1771
|
+
{
|
|
1772
|
+
id: optionId(index),
|
|
1773
|
+
role: "option",
|
|
1774
|
+
"aria-selected": index === activeIndex,
|
|
1775
|
+
onMouseEnter: () => setActiveIndex(index),
|
|
1776
|
+
onClick: () => {
|
|
1777
|
+
onSelect(command);
|
|
1778
|
+
onOpenChange(false);
|
|
1779
|
+
},
|
|
1780
|
+
className: (0, import_core23.cn)(
|
|
1781
|
+
"flex cursor-pointer items-center justify-between px-4 py-2 text-sm",
|
|
1782
|
+
index === activeIndex ? "bg-primary/10 text-foreground" : "text-muted-foreground"
|
|
1783
|
+
),
|
|
1784
|
+
children: renderCommand ? renderCommand(command, { active: index === activeIndex }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
1785
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1786
|
+
command.icon && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0 [&_svg]:size-4", children: command.icon }),
|
|
1787
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "min-w-0", children: [
|
|
1788
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "block truncate", children: command.label }),
|
|
1789
|
+
command.description && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "block text-xs text-muted-foreground", children: command.description })
|
|
1790
|
+
] })
|
|
1791
|
+
] }),
|
|
1792
|
+
command.shortcut && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-mono text-xs", children: command.shortcut })
|
|
1793
|
+
] })
|
|
1794
|
+
}
|
|
1795
|
+
)
|
|
1796
|
+
] }, command.id);
|
|
1797
|
+
})
|
|
1798
|
+
]
|
|
1799
|
+
}
|
|
1800
|
+
)
|
|
1670
1801
|
] })
|
|
1671
1802
|
}
|
|
1672
1803
|
);
|