@humain/ui 2.1.63 → 2.1.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/components/organisms/ai/AIToolCall/AIToolCall.d.ts +9 -3
  2. package/dist/components/organisms/ai/AIToolRun/index.d.ts +1 -1
  3. package/dist/components/organisms/ai/AIToolRun/validation.d.ts +24 -3
  4. package/dist/components/organisms/ai/_shared/format-ai-duration.d.ts +1 -0
  5. package/dist/components/organisms/ai/_shared/workflow-step-renderer.d.ts +1 -0
  6. package/dist/index.js +52 -52
  7. package/dist/index151.js +1 -1
  8. package/dist/index174.js +7 -339
  9. package/dist/index174.js.map +1 -1
  10. package/dist/index175.js +310 -137
  11. package/dist/index175.js.map +1 -1
  12. package/dist/index176.js +148 -174
  13. package/dist/index176.js.map +1 -1
  14. package/dist/index177.js +186 -78
  15. package/dist/index177.js.map +1 -1
  16. package/dist/index178.js +74 -124
  17. package/dist/index178.js.map +1 -1
  18. package/dist/index179.js +133 -1
  19. package/dist/index179.js.map +1 -0
  20. package/dist/index180.js +2 -201
  21. package/dist/index181.js +201 -0
  22. package/dist/{index180.js.map → index181.js.map} +1 -1
  23. package/dist/index183.js +130 -166
  24. package/dist/index183.js.map +1 -1
  25. package/dist/index184.js +195 -983
  26. package/dist/index184.js.map +1 -1
  27. package/dist/index185.js +1069 -369
  28. package/dist/index185.js.map +1 -1
  29. package/dist/index186.js +395 -197
  30. package/dist/index186.js.map +1 -1
  31. package/dist/index187.js +198 -243
  32. package/dist/index187.js.map +1 -1
  33. package/dist/index188.js +263 -3
  34. package/dist/index188.js.map +1 -1
  35. package/dist/index189.js +3 -209
  36. package/dist/index189.js.map +1 -1
  37. package/dist/index190.js +190 -777
  38. package/dist/index190.js.map +1 -1
  39. package/dist/index191.js +771 -252
  40. package/dist/index191.js.map +1 -1
  41. package/dist/index192.js +250 -65
  42. package/dist/index192.js.map +1 -1
  43. package/dist/index193.js +72 -523
  44. package/dist/index193.js.map +1 -1
  45. package/dist/index194.js +537 -144
  46. package/dist/index194.js.map +1 -1
  47. package/dist/index195.js +139 -720
  48. package/dist/index195.js.map +1 -1
  49. package/dist/index196.js +707 -167
  50. package/dist/index196.js.map +1 -1
  51. package/dist/index197.js +175 -151
  52. package/dist/index197.js.map +1 -1
  53. package/dist/index198.js +152 -487
  54. package/dist/index198.js.map +1 -1
  55. package/dist/index199.js +472 -225
  56. package/dist/index199.js.map +1 -1
  57. package/dist/index200.js +236 -260
  58. package/dist/index200.js.map +1 -1
  59. package/dist/index201.js +265 -215
  60. package/dist/index201.js.map +1 -1
  61. package/dist/index202.js +207 -307
  62. package/dist/index202.js.map +1 -1
  63. package/dist/index203.js +302 -135
  64. package/dist/index203.js.map +1 -1
  65. package/dist/index204.js +140 -271
  66. package/dist/index204.js.map +1 -1
  67. package/dist/index205.js +263 -253
  68. package/dist/index205.js.map +1 -1
  69. package/dist/index206.js +244 -137
  70. package/dist/index206.js.map +1 -1
  71. package/dist/index207.js +100 -238
  72. package/dist/index207.js.map +1 -1
  73. package/dist/index208.js +278 -74
  74. package/dist/index208.js.map +1 -1
  75. package/dist/index209.js +56 -97
  76. package/dist/index209.js.map +1 -1
  77. package/dist/index210.js +142 -47
  78. package/dist/index210.js.map +1 -1
  79. package/dist/index211.js +38 -84
  80. package/dist/index211.js.map +1 -1
  81. package/dist/index212.js +72 -252
  82. package/dist/index212.js.map +1 -1
  83. package/dist/index213.js +274 -26
  84. package/dist/index213.js.map +1 -1
  85. package/dist/index214.js +29 -94
  86. package/dist/index214.js.map +1 -1
  87. package/dist/index215.js +98 -25
  88. package/dist/index215.js.map +1 -1
  89. package/dist/index216.js +20 -565
  90. package/dist/index216.js.map +1 -1
  91. package/dist/index217.js +564 -17
  92. package/dist/index217.js.map +1 -1
  93. package/dist/index218.js +20 -23
  94. package/dist/index218.js.map +1 -1
  95. package/dist/index219.js +20 -95
  96. package/dist/index219.js.map +1 -1
  97. package/dist/index220.js +92 -88
  98. package/dist/index220.js.map +1 -1
  99. package/dist/index221.js +97 -29
  100. package/dist/index221.js.map +1 -1
  101. package/dist/index222.js +24 -470
  102. package/dist/index222.js.map +1 -1
  103. package/dist/index223.js +446 -196
  104. package/dist/index223.js.map +1 -1
  105. package/dist/index224.js +199 -729
  106. package/dist/index224.js.map +1 -1
  107. package/dist/index225.js +750 -61
  108. package/dist/index225.js.map +1 -1
  109. package/dist/index226.js +58 -181
  110. package/dist/index226.js.map +1 -1
  111. package/dist/index227.js +175 -259
  112. package/dist/index227.js.map +1 -1
  113. package/dist/index228.js +246 -172
  114. package/dist/index228.js.map +1 -1
  115. package/dist/index229.js +195 -32
  116. package/dist/index229.js.map +1 -1
  117. package/dist/index230.js +12 -40
  118. package/dist/index230.js.map +1 -1
  119. package/dist/index231.js +23 -26
  120. package/dist/index231.js.map +1 -1
  121. package/dist/index232.js +45 -22
  122. package/dist/index232.js.map +1 -1
  123. package/dist/index233.js +27 -48
  124. package/dist/index233.js.map +1 -1
  125. package/dist/index234.js +52 -26
  126. package/dist/index234.js.map +1 -1
  127. package/dist/index235.js +40 -225
  128. package/dist/index235.js.map +1 -1
  129. package/dist/index236.js +217 -39
  130. package/dist/index236.js.map +1 -1
  131. package/dist/index237.js +50 -0
  132. package/dist/index237.js.map +1 -0
  133. package/dist/styles.css +1 -1
  134. package/dist/wc/AIToolCall.js +218 -0
  135. package/dist/wc/AIToolCall.js.map +1 -0
  136. package/dist/wc/hf-ai-tool-call.js +34 -219
  137. package/dist/wc/hf-ai-tool-call.js.map +1 -1
  138. package/dist/wc/hf-ai-tool-run.js +673 -576
  139. package/dist/wc/hf-ai-tool-run.js.map +1 -1
  140. package/dist/wc/workflow-step-renderer.js +79 -78
  141. package/dist/wc/workflow-step-renderer.js.map +1 -1
  142. package/dist/wc-react/AIToolCall.js +218 -0
  143. package/dist/wc-react/AIToolCall.js.map +1 -0
  144. package/dist/wc-react/hf-ai-tool-call.js +32 -217
  145. package/dist/wc-react/hf-ai-tool-call.js.map +1 -1
  146. package/dist/wc-react/hf-ai-tool-run.js +698 -601
  147. package/dist/wc-react/hf-ai-tool-run.js.map +1 -1
  148. package/dist/wc-react/workflow-step-renderer.js +58 -57
  149. package/dist/wc-react/workflow-step-renderer.js.map +1 -1
  150. package/package.json +1 -1
  151. package/skills/humain-ui/SKILL.md +1 -1
  152. package/skills/humain-ui-wc/SKILL.md +1 -1
  153. package/skills/humain-ui-wc.skill +0 -0
  154. package/skills/humain-ui.skill +0 -0
  155. package/dist/index182.js +0 -143
  156. package/dist/index182.js.map +0 -1
  157. package/dist/wc/wrench.js +0 -10
  158. package/dist/wc/wrench.js.map +0 -1
  159. package/dist/wc-react/wrench.js +0 -10
  160. package/dist/wc-react/wrench.js.map +0 -1
package/dist/index186.js CHANGED
@@ -1,221 +1,419 @@
1
- import { cn } from "./index2.js";
2
- import { Badge } from "./index14.js";
3
- import { Avatar } from "./index70.js";
4
- import { FileTypeIcon } from "./index115.js";
5
- import { cva } from "class-variance-authority";
1
+ "use client";
2
+ import { assertNever, cn } from "./index2.js";
3
+ import { Button } from "./index5.js";
4
+ import { Progress } from "./index17.js";
5
+ import { Card } from "./index48.js";
6
+ import { AISource } from "./index173.js";
7
+ import { formatAIDuration } from "./index174.js";
8
+ import { WorkflowStepRenderer } from "./index175.js";
9
+ import { AIToolCallList } from "./index184.js";
10
+ import { validateAIToolRunSnapshot } from "./index185.js";
11
+ import { AlertCircle, Check, ChevronDown, ChevronRight, CirclePause, Clock, Wrench } from "lucide-react";
6
12
  import * as React from "react";
7
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
- //#region src/components/organisms/content/ActivityFeed/ActivityFeed.tsx
9
- var activityFeedVariants = cva("flex flex-col", {
10
- variants: { divider: {
11
- divider: "divide-y divide-border",
12
- connector: "px-6 py-4",
13
- none: "gap-4"
14
- } },
15
- defaultVariants: { divider: "divider" }
16
- });
17
- var activityItemVariants = cva("flex gap-3 relative", {
18
- variants: {
19
- type: {
20
- notifications: "",
21
- messages: ""
22
- },
23
- divider: {
24
- divider: "px-4 py-4",
25
- connector: "pt-0",
26
- none: "px-4 py-4"
13
+ import { jsx, jsxs } from "react/jsx-runtime";
14
+ //#region src/components/organisms/ai/AIToolRun/AIToolRun.tsx
15
+ var MAX_RUNTIME_EXPANDED_STEP_IDS = 1e4;
16
+ var INVALID_RUNTIME_STRING_ARRAY = Symbol("invalid-runtime-string-array");
17
+ var ARRAY_PROTOTYPE_MEMBER_KEYS = Reflect.ownKeys(Array.prototype).filter((key) => key !== "length");
18
+ function cloneRuntimeStringArray(value) {
19
+ try {
20
+ if (!Array.isArray(value)) return INVALID_RUNTIME_STRING_ARRAY;
21
+ const lengthDescriptor = Reflect.getOwnPropertyDescriptor(value, "length");
22
+ if (lengthDescriptor === void 0 || lengthDescriptor.enumerable || !Object.hasOwn(lengthDescriptor, "value") || typeof lengthDescriptor.value !== "number" || !Number.isInteger(lengthDescriptor.value) || lengthDescriptor.value < 0 || lengthDescriptor.value > MAX_RUNTIME_EXPANDED_STEP_IDS || !Object.is(Reflect.get(value, "length"), lengthDescriptor.value)) return INVALID_RUNTIME_STRING_ARRAY;
23
+ for (const key of ARRAY_PROTOTYPE_MEMBER_KEYS) if (Reflect.getOwnPropertyDescriptor(value, key) !== void 0) return INVALID_RUNTIME_STRING_ARRAY;
24
+ const copy = [];
25
+ for (let index = 0; index < lengthDescriptor.value; index += 1) {
26
+ const key = String(index);
27
+ const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
28
+ if (descriptor === void 0 || descriptor.enumerable !== true || !Object.hasOwn(descriptor, "value") || typeof descriptor.value !== "string" || !Object.is(Reflect.get(value, key), descriptor.value)) return INVALID_RUNTIME_STRING_ARRAY;
29
+ copy.push(descriptor.value);
27
30
  }
28
- },
29
- defaultVariants: {
30
- type: "notifications",
31
- divider: "divider"
31
+ return copy;
32
+ } catch {
33
+ return INVALID_RUNTIME_STRING_ARRAY;
32
34
  }
33
- });
34
- function getActivityFeedItemKey(item) {
35
- return item.id ?? `${item.user.name}:${item.timestamp}:${item.activity.text}:${item.activity.link ?? "no-link"}`;
36
- }
37
- function escapeRegExp(value) {
38
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
39
35
  }
40
- function getMessageSegments(message, mentions) {
41
- const mentionSet = /* @__PURE__ */ new Set();
42
- for (const mention of mentions) {
43
- const trimmedMention = mention.trim();
44
- if (trimmedMention) mentionSet.add(trimmedMention);
36
+ function validateRuntimeViewProps({ headingLevel, open, defaultOpen, expandedStepIds, defaultExpandedStepIds }) {
37
+ const issues = [];
38
+ let validatedExpandedStepIds;
39
+ let validatedDefaultExpandedStepIds;
40
+ if (headingLevel !== void 0 && (typeof headingLevel !== "number" || !Number.isInteger(headingLevel) || headingLevel < 2 || headingLevel > 6)) issues.push("headingLevel must be an integer from 2 through 6");
41
+ if (open !== void 0 && typeof open !== "boolean") issues.push("open must be a boolean");
42
+ if (defaultOpen !== void 0 && typeof defaultOpen !== "boolean") issues.push("defaultOpen must be a boolean");
43
+ if (expandedStepIds !== void 0) {
44
+ const cloned = cloneRuntimeStringArray(expandedStepIds);
45
+ if (cloned === INVALID_RUNTIME_STRING_ARRAY) issues.push("expandedStepIds must be an array of strings");
46
+ else validatedExpandedStepIds = cloned;
45
47
  }
46
- const uniqueMentions = Array.from(mentionSet);
47
- if (uniqueMentions.length === 0) return [];
48
- const mentionPattern = new RegExp(`@(?:${uniqueMentions.map(escapeRegExp).join("|")})`, "gi");
49
- const segments = [];
50
- let cursor = 0;
51
- for (const match of message.matchAll(mentionPattern)) {
52
- const start = match.index ?? 0;
53
- const text = match[0];
54
- const end = start + text.length;
55
- if (start > cursor) segments.push({
56
- key: `text:${cursor}:${start}`,
57
- text: message.slice(cursor, start),
58
- isMention: false
59
- });
60
- segments.push({
61
- key: `mention:${start}:${end}:${text.toLowerCase()}`,
62
- text,
63
- isMention: true
64
- });
65
- cursor = end;
48
+ if (defaultExpandedStepIds !== void 0) {
49
+ const cloned = cloneRuntimeStringArray(defaultExpandedStepIds);
50
+ if (cloned === INVALID_RUNTIME_STRING_ARRAY) issues.push("defaultExpandedStepIds must be an array of strings");
51
+ else validatedDefaultExpandedStepIds = cloned;
66
52
  }
67
- if (cursor < message.length) segments.push({
68
- key: `text:${cursor}:${message.length}`,
69
- text: message.slice(cursor),
70
- isMention: false
71
- });
72
- return segments;
73
- }
74
- function ActivityFeedMessageContent({ message, mentions }) {
75
- if (!mentions || mentions.length === 0) return /* @__PURE__ */ jsx(Fragment, { children: `"${message}"` });
76
- return /* @__PURE__ */ jsx(Fragment, { children: getMessageSegments(message, mentions).map((segment) => /* @__PURE__ */ jsx("span", {
77
- className: segment.isMention ? "font-semibold text-primary" : void 0,
78
- children: segment.text
79
- }, segment.key)) });
53
+ if (issues.length > 0) return {
54
+ valid: false,
55
+ issues
56
+ };
57
+ return {
58
+ valid: true,
59
+ value: {
60
+ ...headingLevel === void 0 ? {} : { headingLevel },
61
+ ...open === void 0 ? {} : { open },
62
+ ...defaultOpen === void 0 ? {} : { defaultOpen },
63
+ ...expandedStepIds === void 0 ? {} : { expandedStepIds: validatedExpandedStepIds },
64
+ ...defaultExpandedStepIds === void 0 ? {} : { defaultExpandedStepIds: validatedDefaultExpandedStepIds }
65
+ }
66
+ };
80
67
  }
81
- function ActivityFeedItemContent({ content, expanded }) {
82
- if (!content || expanded === false) return null;
83
- switch (content.type) {
84
- case "file": return /* @__PURE__ */ jsxs("div", {
85
- className: "group/file flex gap-3 items-start w-full mt-3 rounded-lg transition-[background-color,transform] duration-150 ease-out motion-reduce:transition-none hover:bg-muted/40 active:scale-[0.99] motion-reduce:active:scale-100 cursor-default",
86
- children: [/* @__PURE__ */ jsx(FileTypeIcon, {
87
- extension: content.fileExtension,
88
- size: "md"
89
- }), /* @__PURE__ */ jsxs("div", {
90
- className: "flex flex-col min-w-0 flex-1",
91
- children: [/* @__PURE__ */ jsx("p", {
92
- className: "text-sm font-medium text-secondary-foreground truncate",
93
- children: content.fileName
94
- }), /* @__PURE__ */ jsx("p", {
95
- className: "text-sm text-muted-foreground",
96
- children: content.fileSize
97
- })]
98
- })]
68
+ var InvalidAIToolRun = React.forwardRef(({ className, ...sectionProps }, ref) => /* @__PURE__ */ jsx("section", {
69
+ ...sectionProps,
70
+ ref,
71
+ "data-slot": "ai-tool-run",
72
+ role: "alert",
73
+ "aria-label": "Tool run",
74
+ className: cn("w-full min-w-0", className),
75
+ children: "Unable to display tool run."
76
+ }));
77
+ InvalidAIToolRun.displayName = "InvalidAIToolRun";
78
+ var RUN_STATUS_LABELS = {
79
+ ready: "Ready",
80
+ running: "Running",
81
+ paused: "Paused",
82
+ completed: "Completed",
83
+ error: "Failed"
84
+ };
85
+ var STANDARD_ACTION_LABELS = {
86
+ start: "Start",
87
+ pause: "Pause",
88
+ resume: "Resume",
89
+ retry: "Retry",
90
+ dismiss: "Dismiss"
91
+ };
92
+ var PAUSED_PROGRESS_CLASS_NAME = "[&_[data-slot=progress-indicator]]:!transition-none [&_[data-slot=progress-indicator]]:!animate-none";
93
+ function RunStatusIcon({ status }) {
94
+ switch (status) {
95
+ case "ready": return /* @__PURE__ */ jsx(Wrench, {
96
+ "aria-hidden": "true",
97
+ className: "size-4 text-muted-foreground"
99
98
  });
100
- case "message": return /* @__PURE__ */ jsx("div", {
101
- className: "mt-3 border border-border rounded-ee-md rounded-es-md rounded-se-md p-3 shadow-xs w-full transition-shadow duration-200 ease-out hover:shadow-sm motion-reduce:transition-none",
102
- children: /* @__PURE__ */ jsx("p", {
103
- className: "text-sm text-secondary-foreground",
104
- children: /* @__PURE__ */ jsx(ActivityFeedMessageContent, {
105
- message: content.message,
106
- mentions: content.mentions
107
- })
108
- })
99
+ case "running": return /* @__PURE__ */ jsx(Clock, {
100
+ "aria-hidden": "true",
101
+ className: "size-4 text-primary animate-pulse motion-reduce:animate-none"
102
+ });
103
+ case "paused": return /* @__PURE__ */ jsx(CirclePause, {
104
+ "aria-hidden": "true",
105
+ className: "size-4 text-warning"
109
106
  });
110
- case "labels": return /* @__PURE__ */ jsx("div", {
111
- className: "flex flex-wrap gap-1 mt-3",
112
- children: content.labels.map((label, i) => /* @__PURE__ */ jsx(Badge, {
113
- variant: "outline",
114
- color: label.color || "primary",
115
- size: "sm",
116
- className: "delight-stagger transition-transform duration-150 ease-out motion-reduce:transition-none hover:scale-105 motion-reduce:hover:scale-100",
117
- style: { "--delight-delay": `${i * 50}ms` },
118
- children: label.text
119
- }, label.text))
107
+ case "completed": return /* @__PURE__ */ jsx(Check, {
108
+ "aria-hidden": "true",
109
+ className: "size-4 text-success"
120
110
  });
121
- default: return null;
111
+ case "error": return /* @__PURE__ */ jsx(AlertCircle, {
112
+ "aria-hidden": "true",
113
+ className: "size-4 text-destructive"
114
+ });
115
+ default: return assertNever(status);
122
116
  }
123
117
  }
124
- var ActivityFeedItem = React.memo(React.forwardRef(({ className, user, timestamp, dateTime, activity, content, unread = false, avatarSize = "lg", divider = "divider", feedType = "notifications", userHandle, expanded, isLast = false, ...props }, ref) => {
125
- return /* @__PURE__ */ jsxs("article", {
126
- ref,
127
- "data-slot": "activity-feed-item",
128
- "aria-label": `${user.name}: ${activity.text}${activity.link ? ` ${activity.link}` : ""}`,
129
- className: cn(activityItemVariants({
130
- type: feedType,
131
- divider
132
- }), "transition-colors duration-150 ease-out motion-reduce:transition-none", "hover:bg-muted/30", className),
133
- ...props,
118
+ RunStatusIcon.displayName = "RunStatusIcon";
119
+ function getActionLabel(action) {
120
+ if (action.kind === "custom") return action.label;
121
+ return action.label ?? STANDARD_ACTION_LABELS[action.kind];
122
+ }
123
+ function getPoliteAnnouncement(run) {
124
+ if (run.status === "error") return "";
125
+ const activeStep = run.activeStepId === void 0 ? void 0 : run.steps.find((step) => step.toolCall.toolCallId === run.activeStepId);
126
+ const statusLabel = RUN_STATUS_LABELS[run.status];
127
+ return activeStep ? `${statusLabel}. Current step: ${activeStep.title ?? activeStep.toolCall.toolName}.` : `${statusLabel}.`;
128
+ }
129
+ function getWorkflowStepStatus(runStatus, step) {
130
+ const toolStatus = step.toolCall.status;
131
+ switch (toolStatus) {
132
+ case "pending": return "pending";
133
+ case "running": return runStatus === "paused" ? "suspended" : "running";
134
+ case "success": return "completed";
135
+ case "error": return "error";
136
+ default: return assertNever(toolStatus);
137
+ }
138
+ }
139
+ function AIToolRunStepContent({ progress, sources, title, paused, technicalDetails }) {
140
+ const failedToolCallIds = technicalDetails?.toolCalls.flatMap((toolCall) => toolCall.status === "error" ? [toolCall.toolCallId] : []) ?? [];
141
+ return /* @__PURE__ */ jsxs("div", {
142
+ className: "grid min-w-0 gap-3",
134
143
  children: [
135
- /* @__PURE__ */ jsxs("div", {
136
- className: cn("flex flex-col items-center gap-0.5 self-stretch shrink-0", divider === "connector" && !isLast && "pb-0.5"),
137
- children: [/* @__PURE__ */ jsx(Avatar, {
138
- src: user.avatarSrc,
139
- fallback: user.name,
140
- size: avatarSize,
141
- indicator: user.online === true ? "online" : user.online === false ? "offline" : void 0
142
- }), divider === "connector" && !isLast && /* @__PURE__ */ jsx("div", { className: "flex-1 w-0.5 min-h-4 rounded-sm bg-border delight-connector-grow" })]
144
+ progress && /* @__PURE__ */ jsx(Progress, {
145
+ value: progress.value,
146
+ label: progress.label,
147
+ subLabel: progress.meta,
148
+ className: paused ? PAUSED_PROGRESS_CLASS_NAME : void 0
143
149
  }),
144
- /* @__PURE__ */ jsxs("div", {
145
- className: cn("flex flex-col flex-1 min-w-0", divider === "connector" && "pb-8"),
146
- children: [/* @__PURE__ */ jsxs("div", {
147
- className: "flex flex-col",
148
- children: [/* @__PURE__ */ jsxs("div", {
149
- className: "flex items-center gap-2 flex-wrap",
150
- children: [
151
- /* @__PURE__ */ jsx("span", {
152
- className: "text-sm font-medium text-secondary-foreground",
153
- children: user.name
154
- }),
155
- feedType === "messages" && userHandle && /* @__PURE__ */ jsxs("span", {
156
- className: "text-sm text-muted-foreground",
157
- children: ["@", userHandle]
158
- }),
159
- dateTime ? /* @__PURE__ */ jsx("time", {
160
- dateTime,
161
- className: "text-xs text-muted-foreground",
162
- children: timestamp
163
- }) : /* @__PURE__ */ jsx("span", {
164
- className: "text-xs text-muted-foreground",
165
- children: timestamp
166
- })
167
- ]
168
- }), /* @__PURE__ */ jsxs("p", {
169
- className: "text-sm text-muted-foreground",
170
- children: [activity.text, activity.link && /* @__PURE__ */ jsxs(Fragment, { children: [" ", activity.linkHref ? /* @__PURE__ */ jsx("a", {
171
- href: activity.linkHref,
172
- className: "font-medium text-primary hover:text-primary/80 transition-colors duration-150 ease-out focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1 rounded-sm",
173
- children: activity.link
174
- }) : /* @__PURE__ */ jsx("span", {
175
- className: "font-medium text-secondary-foreground",
176
- children: activity.link
177
- })] })]
178
- })]
179
- }), /* @__PURE__ */ jsx(ActivityFeedItemContent, {
180
- content,
181
- expanded
182
- })]
150
+ sources.length > 0 && /* @__PURE__ */ jsx("ul", {
151
+ "aria-label": `Sources for ${title}`,
152
+ className: "grid min-w-0 gap-2",
153
+ children: sources.map((item, index) => /* @__PURE__ */ jsx("li", {
154
+ className: "flex min-w-0 items-center gap-2",
155
+ children: item.kind === "reference" ? /* @__PURE__ */ jsx("span", {
156
+ "data-slot": "ai-tool-run-reference",
157
+ className: "min-w-0 truncate text-sm text-secondary-foreground",
158
+ title: item.description,
159
+ children: item.title
160
+ }) : /* @__PURE__ */ jsx(AISource, {
161
+ source: item,
162
+ variant: "minimal",
163
+ showTooltip: false,
164
+ className: "min-w-0 max-w-none"
165
+ })
166
+ }, `${item.id}-${index}`))
183
167
  }),
184
- unread && /* @__PURE__ */ jsx("div", {
185
- className: "absolute top-2 end-1 size-2.5",
186
- "aria-hidden": "true",
187
- children: /* @__PURE__ */ jsx("div", { className: "size-2 rounded-full bg-primary delight-unread-pulse" })
168
+ technicalDetails && technicalDetails.toolCalls.length > 0 && /* @__PURE__ */ jsxs("div", {
169
+ className: "grid min-w-0 gap-2",
170
+ children: [technicalDetails.label && /* @__PURE__ */ jsx("p", {
171
+ className: "text-xs font-medium text-secondary-foreground",
172
+ children: technicalDetails.label
173
+ }), /* @__PURE__ */ jsx(AIToolCallList, {
174
+ toolCalls: technicalDetails.toolCalls,
175
+ defaultOpenToolCallIds: failedToolCallIds
176
+ })]
188
177
  })
189
178
  ]
190
179
  });
191
- }));
192
- ActivityFeedItem.displayName = "ActivityFeedItem";
193
- var ActivityFeed = React.forwardRef(({ className, divider = "divider", items, type = "notifications", loading, children, ...props }, ref) => {
194
- return /* @__PURE__ */ jsx("div", {
180
+ }
181
+ AIToolRunStepContent.displayName = "AIToolRunStepContent";
182
+ function toWorkflowStep(runStatus, step, sourcesById) {
183
+ const title = step.title ?? step.toolCall.toolName;
184
+ const stepSources = (step.sourceIds ?? []).flatMap((sourceId) => {
185
+ const source = sourcesById.get(sourceId);
186
+ return source === void 0 ? [] : [source];
187
+ });
188
+ const hasContent = step.progress !== void 0 || stepSources.length > 0 || step.technicalDetails !== void 0;
189
+ return {
190
+ id: step.toolCall.toolCallId,
191
+ title,
192
+ description: step.description,
193
+ contextLabel: step.context?.label,
194
+ status: getWorkflowStepStatus(runStatus, step),
195
+ content: hasContent ? /* @__PURE__ */ jsx(AIToolRunStepContent, {
196
+ progress: step.progress,
197
+ sources: stepSources,
198
+ title,
199
+ paused: runStatus === "paused",
200
+ technicalDetails: step.technicalDetails
201
+ }) : void 0,
202
+ durationMs: step.durationMs,
203
+ error: step.toolCall.status === "error" ? step.toolCall.error : void 0
204
+ };
205
+ }
206
+ function useAIToolRunOpenState({ open, defaultOpen, onOpenChange }) {
207
+ const isControlled = open !== void 0;
208
+ const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen ?? true);
209
+ const lastControlledOpenRef = React.useRef(open ?? uncontrolledOpen);
210
+ const wasControlledRef = React.useRef(isControlled);
211
+ React.useLayoutEffect(() => {
212
+ if (open !== void 0) lastControlledOpenRef.current = open;
213
+ }, [open]);
214
+ React.useLayoutEffect(() => {
215
+ const wasControlled = wasControlledRef.current;
216
+ wasControlledRef.current = isControlled;
217
+ if (isControlled || !wasControlled) return;
218
+ setUncontrolledOpen((currentOpen) => currentOpen === lastControlledOpenRef.current ? currentOpen : lastControlledOpenRef.current);
219
+ }, [isControlled]);
220
+ const setOpen = React.useCallback((nextOpen) => {
221
+ if (!isControlled) setUncontrolledOpen(nextOpen);
222
+ onOpenChange?.(nextOpen);
223
+ }, [isControlled, onOpenChange]);
224
+ return [isControlled ? open : uncontrolledOpen, setOpen];
225
+ }
226
+ var AIToolRunPresentation = React.forwardRef(({ run, headingLevel = 2, open, defaultOpen, onOpenChange, expandedStepIds, defaultExpandedStepIds, onExpandedStepIdsChange, onAction, className, ...sectionProps }, ref) => {
227
+ const headingId = React.useId();
228
+ const detailsId = React.useId();
229
+ const Heading = `h${headingLevel}`;
230
+ const [isOpen, setIsOpen] = useAIToolRunOpenState({
231
+ open,
232
+ defaultOpen,
233
+ onOpenChange
234
+ });
235
+ const sourcesById = React.useMemo(() => new Map((run.sources ?? []).map((source) => [source.id, source])), [run.sources]);
236
+ const workflowSteps = React.useMemo(() => run.steps.map((step) => toWorkflowStep(run.status, step, sourcesById)), [
237
+ run.status,
238
+ run.steps,
239
+ sourcesById
240
+ ]);
241
+ const initialExpandedStepIds = React.useMemo(() => {
242
+ const requested = new Set(defaultExpandedStepIds);
243
+ for (const step of run.steps) if (step.toolCall.status === "error") requested.add(step.toolCall.toolCallId);
244
+ return run.steps.flatMap((step) => requested.has(step.toolCall.toolCallId) ? [step.toolCall.toolCallId] : []);
245
+ }, [defaultExpandedStepIds, run.steps]);
246
+ const rootError = run.status === "error" ? run.error.message : void 0;
247
+ const politeAnnouncement = getPoliteAnnouncement(run);
248
+ const { "aria-busy": _ariaBusy, ...nativeSectionProps } = sectionProps;
249
+ return /* @__PURE__ */ jsxs("section", {
250
+ ...nativeSectionProps,
251
+ ref,
252
+ "data-slot": "ai-tool-run",
253
+ "aria-labelledby": headingId,
254
+ className: cn("relative w-full min-w-0", className),
255
+ children: [/* @__PURE__ */ jsxs(Card, {
256
+ "aria-busy": run.status === "running" ? true : void 0,
257
+ className: "rounded-2xl",
258
+ children: [
259
+ /* @__PURE__ */ jsxs(Card.Header, { children: [/* @__PURE__ */ jsxs("div", {
260
+ className: "grid min-w-0 gap-1",
261
+ children: [
262
+ /* @__PURE__ */ jsxs("div", {
263
+ className: "flex min-w-0 items-center gap-2 text-xs font-medium text-secondary-foreground",
264
+ children: [
265
+ /* @__PURE__ */ jsx(RunStatusIcon, { status: run.status }),
266
+ /* @__PURE__ */ jsxs("span", { children: ["Status: ", RUN_STATUS_LABELS[run.status]] }),
267
+ run.durationMs !== void 0 && /* @__PURE__ */ jsx("span", { children: formatAIDuration(run.durationMs) })
268
+ ]
269
+ }),
270
+ /* @__PURE__ */ jsx(Heading, {
271
+ id: headingId,
272
+ className: "min-w-0 truncate text-base font-semibold text-foreground",
273
+ children: run.header.title
274
+ }),
275
+ run.header.description && /* @__PURE__ */ jsx("p", {
276
+ className: "line-clamp-2 text-sm text-secondary-foreground",
277
+ children: run.header.description
278
+ }),
279
+ run.header.metadata && run.header.metadata.length > 0 && /* @__PURE__ */ jsx("dl", {
280
+ className: "flex flex-wrap gap-x-3 gap-y-1 text-xs text-secondary-foreground",
281
+ children: run.header.metadata.map((item, index) => /* @__PURE__ */ jsxs("div", {
282
+ className: "flex min-w-0 items-center gap-1",
283
+ children: [/* @__PURE__ */ jsxs("dt", {
284
+ className: "text-muted-foreground",
285
+ children: [item.label, ":"]
286
+ }), /* @__PURE__ */ jsx("dd", {
287
+ className: "min-w-0 truncate",
288
+ children: item.value
289
+ })]
290
+ }, `${item.label}-${index}`))
291
+ }),
292
+ !isOpen && run.progress && /* @__PURE__ */ jsx(Progress, {
293
+ value: run.progress.value,
294
+ label: run.progress.label,
295
+ subLabel: run.progress.meta,
296
+ className: run.status === "paused" ? PAUSED_PROGRESS_CLASS_NAME : void 0
297
+ })
298
+ ]
299
+ }), /* @__PURE__ */ jsx(Card.Action, { children: /* @__PURE__ */ jsx(Button, {
300
+ appearance: "ghost",
301
+ variant: "secondary",
302
+ size: "icon-xl",
303
+ iconOnly: true,
304
+ "aria-label": isOpen ? "Collapse tool run" : "Expand tool run",
305
+ "aria-expanded": isOpen,
306
+ "aria-controls": detailsId,
307
+ onClick: () => setIsOpen(!isOpen),
308
+ children: isOpen ? /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronRight, {
309
+ "aria-hidden": "true",
310
+ className: "rtl:rotate-180"
311
+ })
312
+ }) })] }),
313
+ /* @__PURE__ */ jsxs(Card.Content, {
314
+ id: detailsId,
315
+ hidden: !isOpen,
316
+ className: "grid min-w-0 gap-4",
317
+ children: [
318
+ run.progress && /* @__PURE__ */ jsx(Progress, {
319
+ value: run.progress.value,
320
+ label: run.progress.label,
321
+ subLabel: run.progress.meta,
322
+ className: run.status === "paused" ? PAUSED_PROGRESS_CLASS_NAME : void 0
323
+ }),
324
+ rootError && /* @__PURE__ */ jsxs("div", {
325
+ className: "flex min-w-0 items-start gap-2 rounded-lg border border-destructive/50 bg-destructive/10 p-3",
326
+ children: [/* @__PURE__ */ jsx(AlertCircle, {
327
+ "aria-hidden": "true",
328
+ className: "mt-0.5 size-4 shrink-0 text-destructive"
329
+ }), /* @__PURE__ */ jsx("p", {
330
+ className: "min-w-0 text-sm text-destructive",
331
+ children: rootError
332
+ })]
333
+ }),
334
+ /* @__PURE__ */ jsx(WorkflowStepRenderer, {
335
+ appearance: "timeline",
336
+ steps: workflowSteps,
337
+ activeStepId: run.activeStepId,
338
+ expandedStepIds,
339
+ defaultExpandedStepIds: initialExpandedStepIds,
340
+ onExpandedStepIdsChange,
341
+ renderItems: isOpen
342
+ }, run.runId)
343
+ ]
344
+ }),
345
+ run.actions && run.actions.length > 0 && /* @__PURE__ */ jsx(Card.Footer, {
346
+ className: "flex flex-wrap gap-2",
347
+ children: run.actions.map((action) => /* @__PURE__ */ jsx(Button, {
348
+ appearance: "outline",
349
+ variant: "secondary",
350
+ disabled: action.disabled,
351
+ loading: action.loading,
352
+ "aria-label": getActionLabel(action),
353
+ className: "min-w-0 w-full max-w-full min-[480px]:w-auto h-auto min-h-9 whitespace-normal break-words [overflow-wrap:anywhere] [&>span]:min-w-0",
354
+ onClick: () => {
355
+ if (action.disabled || action.loading) return;
356
+ onAction?.({
357
+ runId: run.runId,
358
+ actionId: action.id,
359
+ kind: action.kind
360
+ });
361
+ },
362
+ children: getActionLabel(action)
363
+ }, action.id))
364
+ })
365
+ ]
366
+ }), rootError ? /* @__PURE__ */ jsx("div", {
367
+ role: "alert",
368
+ "aria-live": "assertive",
369
+ className: "sr-only left-0 top-0",
370
+ children: rootError
371
+ }) : /* @__PURE__ */ jsx("div", {
372
+ role: "status",
373
+ "aria-live": "polite",
374
+ className: "sr-only left-0 top-0",
375
+ children: politeAnnouncement
376
+ })]
377
+ });
378
+ });
379
+ AIToolRunPresentation.displayName = "AIToolRunPresentation";
380
+ var AIToolRunRuntimeBoundary = React.forwardRef((props, ref) => {
381
+ const { run, headingLevel, open, defaultOpen, expandedStepIds, defaultExpandedStepIds, dangerouslySetInnerHTML: unsafeHtml, onOpenChange, onExpandedStepIdsChange, onAction, ...sectionProps } = props;
382
+ const snapshotResult = validateAIToolRunSnapshot(run);
383
+ const viewResult = validateRuntimeViewProps({
384
+ headingLevel,
385
+ open,
386
+ defaultOpen,
387
+ expandedStepIds,
388
+ defaultExpandedStepIds
389
+ });
390
+ if (!snapshotResult.valid || !viewResult.valid) return /* @__PURE__ */ jsx(InvalidAIToolRun, {
391
+ ...sectionProps,
392
+ ref
393
+ });
394
+ return /* @__PURE__ */ jsx(AIToolRunPresentation, {
395
+ ...sectionProps,
396
+ ...viewResult.value,
397
+ onOpenChange,
398
+ onExpandedStepIdsChange,
399
+ onAction,
195
400
  ref,
196
- "data-slot": "activity-feed",
197
- role: "feed",
198
- "aria-label": "Activity feed",
199
- "aria-busy": loading || void 0,
200
- className: cn(activityFeedVariants({ divider }), className),
201
- ...props,
202
- children: items ? items.map((item, index) => /* @__PURE__ */ jsx(ActivityFeedItem, {
203
- ...item,
204
- "aria-setsize": items.length,
205
- "aria-posinset": index + 1,
206
- divider: divider ?? "divider",
207
- feedType: type,
208
- isLast: index === items.length - 1,
209
- className: cn("delight-stagger", item.className),
210
- style: {
211
- "--delight-delay": `${index * 60}ms`,
212
- ...item.style
213
- }
214
- }, getActivityFeedItemKey(item))) : children
401
+ run: snapshotResult.value
215
402
  });
216
403
  });
217
- ActivityFeed.displayName = "ActivityFeed";
404
+ /**
405
+ * Displays one validated AI tool run with lifecycle, progress, sources,
406
+ * disclosure, and action intents.
407
+ *
408
+ * @llms Validated AI tool-run timeline with lifecycle, progress, sources, disclosure, and actions
409
+ */
410
+ var AIToolRun = React.forwardRef((props, ref) => /* @__PURE__ */ jsx(AIToolRunRuntimeBoundary, {
411
+ ...props,
412
+ ref
413
+ }));
414
+ AIToolRunRuntimeBoundary.displayName = "AIToolRunRuntimeBoundary";
415
+ AIToolRun.displayName = "AIToolRun";
218
416
  //#endregion
219
- export { ActivityFeed, ActivityFeedItem, activityFeedVariants, activityItemVariants };
417
+ export { AIToolRun, AIToolRunRuntimeBoundary };
220
418
 
221
419
  //# sourceMappingURL=index186.js.map