@reforma/components 0.6.0 → 0.6.2

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.
@@ -1 +1 @@
1
- .MessagePhaseSection_root_Cqd0t1{display:flex;flex-direction:column;gap:var(--spacing-lg);margin-top:var(--spacing-md);width:100%;color:var(--color-text);font-weight:400;font-size:var(--text-md);line-height:var(--leading-md);font-family:Onest,sans-serif;letter-spacing:0}.MessagePhaseSection_root_Cqd0t1:first-child{margin-top:0}.MessagePhaseSection_header_a11Bwm{width:100%;--reforma-button-opacity--hover: 1}.MessagePhaseSection_headerContent_6gdB1H{justify-content:start;gap:var(--spacing-md);width:100%}.MessagePhaseSection_headerTitle_RT3fFZ{display:flex;flex-shrink:0;overflow:hidden}.MessagePhaseSection_headerSummary_HTSuia{display:flex;align-items:center;gap:var(--spacing-md);min-width:0;font-weight:400;font-size:var(--text-sm);line-height:var(--leading-sm);font-family:Onest,sans-serif;letter-spacing:0}.MessagePhaseSection_chevronIcon_7lOW0r{flex-shrink:0;opacity:0;transition:all .15s ease}.MessagePhaseSection_chevronIcon_7lOW0r[aria-expanded=true]{opacity:1}.MessagePhaseSection_header_a11Bwm:hover .MessagePhaseSection_chevronIcon_7lOW0r,.MessagePhaseSection_header_a11Bwm:focus-visible .MessagePhaseSection_chevronIcon_7lOW0r{opacity:1}.MessagePhaseSection_phasePanel_UxIl4o{position:relative;padding-right:var(--spacing-md);width:100%}.MessagePhaseSection_phasePanelContent_xFRBiK{display:flex;flex-direction:column;gap:var(--spacing-lg)}
1
+ .MessagePhaseSection_root_Cqd0t1{display:flex;flex-direction:column;gap:var(--spacing-lg);margin-top:var(--spacing-md);width:100%;color:var(--color-text);font-weight:400;font-size:var(--text-md);line-height:var(--leading-md);font-family:Onest,sans-serif;letter-spacing:0}.MessagePhaseSection_root_Cqd0t1:first-child{margin-top:0}.MessagePhaseSection_header_a11Bwm{width:100%;--reforma-button-opacity--hover: 1}.MessagePhaseSection_headerContent_6gdB1H{justify-content:start;gap:var(--spacing-md);width:100%}.MessagePhaseSection_headerTitle_RT3fFZ{display:flex;flex-shrink:0;overflow:hidden}.MessagePhaseSection_headerSummary_HTSuia{display:flex;align-items:center;gap:var(--spacing-md);min-width:0;font-weight:400;font-size:var(--text-sm);line-height:var(--leading-sm);font-family:Onest,sans-serif;letter-spacing:0}.MessagePhaseSection_chevronIcon_7lOW0r{flex-shrink:0;opacity:0;transition:all .15s ease}.MessagePhaseSection_chevronIcon_7lOW0r[aria-expanded=true]{opacity:1}.MessagePhaseSection_header_a11Bwm:hover .MessagePhaseSection_chevronIcon_7lOW0r,.MessagePhaseSection_header_a11Bwm:focus-visible .MessagePhaseSection_chevronIcon_7lOW0r{opacity:1}.MessagePhaseSection_phasePanel_UxIl4o{position:relative;width:100%}.MessagePhaseSection_phasePanelContent_xFRBiK{display:flex;flex-direction:column;gap:var(--spacing-lg)}
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Assistant turn segments and streaming pending loader.
3
3
  * A finished text answer folds the work into one "Worked for …" disclosure.
4
- * Cancelled turns and turns that do not end on text keep the phase rows open.
4
+ * The latest turn keeps its phase rows open when cancelled or not ending on text;
5
+ * an older one folds them anyway.
5
6
  */
6
7
  export declare const MessageAssistantBody: (({ hideSources, }?: {
7
8
  /** Editor footer owns citations — drop in-body Sources groups. */
@@ -1 +1 @@
1
- {"version":3,"file":"MessageAssistantBody.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/turn/MessageAssistantBody.tsx"],"names":[],"mappings":"AAmJA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,uBAE9B;IACC,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;IAFG,kEAAkE;kBACpD,OAAO;;uCAFtB;QACC,kEAAkE;QAClE,WAAW,CAAC,EAAE,OAAO,CAAC;KACzB;CA8EC,CAAC"}
1
+ {"version":3,"file":"MessageAssistantBody.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/turn/MessageAssistantBody.tsx"],"names":[],"mappings":"AAmJA;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,uBAE9B;IACC,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;IAFG,kEAAkE;kBACpD,OAAO;;uCAFtB;QACC,kEAAkE;QAClE,WAAW,CAAC,EAAE,OAAO,CAAC;KACzB;CAmFC,CAAC"}
@@ -1,18 +1,18 @@
1
- import { ChevronDown as A } from "@reforma/icons/8";
2
- import { cn as C } from "@reforma/lib";
3
- import { observer as T } from "mobx-react-lite";
4
- import { Button as F } from "../../../Button/Button.js";
5
- import { Collapsible as y, useCollapsible as P, CollapsibleTrigger as L, CollapsibleContent as M } from "../../../Collapsible/Collapsible.js";
6
- import { For as W } from "../../../For/For.js";
7
- import { Show as w } from "../../../Show/Show.js";
1
+ import { ChevronDown as C } from "@reforma/icons/8";
2
+ import { cn as T } from "@reforma/lib";
3
+ import { observer as F } from "mobx-react-lite";
4
+ import { Button as y } from "../../../Button/Button.js";
5
+ import { Collapsible as L, useCollapsible as P, CollapsibleTrigger as M, CollapsibleContent as W } from "../../../Collapsible/Collapsible.js";
6
+ import { For as N } from "../../../For/For.js";
7
+ import { Show as u } from "../../../Show/Show.js";
8
8
  import { ConversationPendingLoader as S } from "../../Conversation/ConversationPendingLoader.js";
9
- import { streamingPhaseActiveIndex as N, partsFromSegmentGroups as j } from "../normalize/normalizeMessageParts.js";
10
- import { MessagePhaseSection as B } from "../segments/MessagePhaseSection.js";
9
+ import { streamingPhaseActiveIndex as j, partsFromSegmentGroups as B } from "../normalize/normalizeMessageParts.js";
10
+ import { MessagePhaseSection as E } from "../segments/MessagePhaseSection.js";
11
11
  import v from "./Message.module.css.js";
12
- import { useMessageTurn as E } from "./messageTurnContext.js";
13
- import { splitFinishedWork as $, workedForLabel as D } from "./workedCollapse.js";
14
- import { jsx as r, jsxs as d, Fragment as b } from "react/jsx-runtime";
15
- function G(t) {
12
+ import { useMessageTurn as $ } from "./messageTurnContext.js";
13
+ import { splitFinishedWork as D, workedForLabel as G } from "./workedCollapse.js";
14
+ import { jsx as r, jsxs as p, Fragment as b } from "react/jsx-runtime";
15
+ function I(t) {
16
16
  const e = [];
17
17
  for (const s of t) {
18
18
  const n = s.groups.filter((l) => l.kind !== "sources");
@@ -23,34 +23,34 @@ function G(t) {
23
23
  }
24
24
  return e;
25
25
  }
26
- function k({
26
+ function w({
27
27
  segments: t,
28
28
  messageId: e,
29
29
  isStreaming: s,
30
30
  isLiveMessage: n,
31
31
  turnActive: l,
32
- phaseActiveIndex: u,
32
+ phaseActiveIndex: h,
33
33
  getPhaseStats: o,
34
- lastPart: p,
34
+ lastPart: d,
35
35
  loaderParts: f,
36
36
  markTail: a
37
37
  }) {
38
- return /* @__PURE__ */ r(W, {
38
+ return /* @__PURE__ */ r(N, {
39
39
  each: t,
40
40
  children: (i, c, {
41
41
  isLast: g
42
42
  }) => {
43
43
  const m = a && g;
44
- return /* @__PURE__ */ r(B, {
44
+ return /* @__PURE__ */ r(E, {
45
45
  segment: i,
46
46
  messageId: e,
47
47
  isStreaming: s,
48
48
  isLiveMessage: n,
49
49
  isLastSegment: m,
50
- streamActive: l && (m || c === u),
51
- fileStats: i.layout === "grouped" ? o?.(j(i.groups)) : void 0,
50
+ streamActive: l && (m || c === h),
51
+ fileStats: i.layout === "grouped" ? o?.(B(i.groups)) : void 0,
52
52
  children: m && s ? /* @__PURE__ */ r(S, {
53
- lastPart: p,
53
+ lastPart: d,
54
54
  messageId: e,
55
55
  parts: f
56
56
  }) : null
@@ -58,93 +58,94 @@ function k({
58
58
  }
59
59
  });
60
60
  }
61
- function I({
61
+ function O({
62
62
  label: t
63
63
  }) {
64
64
  const {
65
65
  state: e
66
66
  } = P();
67
- return /* @__PURE__ */ r(L, {
67
+ return /* @__PURE__ */ r(M, {
68
68
  asChild: !0,
69
- children: /* @__PURE__ */ d(F, {
69
+ children: /* @__PURE__ */ p(y, {
70
70
  type: "button",
71
71
  variant: "inline",
72
72
  color: "secondary",
73
73
  className: v.workedTrigger,
74
- children: [t, /* @__PURE__ */ r(A, {
75
- className: C("chevron", "next"),
74
+ children: [t, /* @__PURE__ */ r(C, {
75
+ className: T("chevron", "next"),
76
76
  "aria-expanded": e.isExpanded,
77
77
  "aria-hidden": !0
78
78
  })]
79
79
  })
80
80
  });
81
81
  }
82
- function O({
82
+ function R({
83
83
  children: t
84
84
  }) {
85
85
  const {
86
86
  state: e
87
87
  } = P();
88
- return /* @__PURE__ */ r(w, {
88
+ return /* @__PURE__ */ r(u, {
89
89
  when: e.isExpanded,
90
- children: /* @__PURE__ */ r(M, {
90
+ children: /* @__PURE__ */ r(W, {
91
91
  className: v.workedPanel,
92
92
  children: t
93
93
  })
94
94
  });
95
95
  }
96
- function R({
96
+ function q({
97
97
  label: t,
98
98
  children: e
99
99
  }) {
100
- return /* @__PURE__ */ d(y, {
100
+ return /* @__PURE__ */ p(L, {
101
101
  className: v.worked,
102
102
  defaultOpen: !1,
103
- children: [/* @__PURE__ */ r(I, {
103
+ children: [/* @__PURE__ */ r(O, {
104
104
  label: t
105
- }), /* @__PURE__ */ r(O, {
105
+ }), /* @__PURE__ */ r(R, {
106
106
  children: e
107
107
  })]
108
108
  });
109
109
  }
110
- const te = T(({
110
+ const se = F(({
111
111
  hideSources: t = !1
112
112
  } = {}) => {
113
- const e = E();
113
+ const e = $();
114
114
  if (e?.role !== "assistant" || e.message.role !== "assistant")
115
115
  return null;
116
116
  const {
117
117
  messageId: s,
118
118
  segments: n,
119
119
  lastPart: l,
120
- turnActive: u,
120
+ turnActive: h,
121
121
  isStreaming: o,
122
- isLastMessage: p,
122
+ isLastMessage: d,
123
123
  getPhaseStats: f
124
- } = e, a = t ? G(n) : n, i = e.message.parts, c = e.message.metadata;
124
+ } = e, a = t ? I(n) : n, i = e.message.parts, c = e.message.metadata;
125
125
  if (a.length === 0 && !o)
126
126
  return null;
127
- const g = N(a, o), m = $(a, {
127
+ const g = j(a, o), m = D(a, {
128
128
  streaming: o,
129
- cancelled: c?.stopReason === "cancelled"
130
- }), h = {
129
+ cancelled: c?.stopReason === "cancelled",
130
+ superseded: !d
131
+ }), k = {
131
132
  messageId: s,
132
133
  isStreaming: o,
133
- isLiveMessage: p,
134
- turnActive: u,
134
+ isLiveMessage: d,
135
+ turnActive: h,
135
136
  phaseActiveIndex: g,
136
137
  getPhaseStats: f,
137
138
  lastPart: l,
138
139
  loaderParts: i
139
140
  };
140
- return /* @__PURE__ */ r(w, {
141
+ return /* @__PURE__ */ r(u, {
141
142
  when: m,
142
- fallback: /* @__PURE__ */ d(b, {
143
- children: [/* @__PURE__ */ r(k, {
144
- ...h,
143
+ fallback: /* @__PURE__ */ p(b, {
144
+ children: [/* @__PURE__ */ r(w, {
145
+ ...k,
145
146
  segments: a,
146
147
  markTail: !0
147
- }), /* @__PURE__ */ r(w, {
148
+ }), /* @__PURE__ */ r(u, {
148
149
  when: o && a.length === 0,
149
150
  children: /* @__PURE__ */ r(S, {
150
151
  lastPart: l,
@@ -153,23 +154,26 @@ const te = T(({
153
154
  })
154
155
  })]
155
156
  }),
156
- children: (x) => /* @__PURE__ */ d(b, {
157
- children: [/* @__PURE__ */ r(R, {
158
- label: D(c?.startedAt, c?.endedAt),
159
- children: /* @__PURE__ */ r(k, {
160
- ...h,
157
+ children: (x) => /* @__PURE__ */ p(b, {
158
+ children: [/* @__PURE__ */ r(q, {
159
+ label: G(c?.startedAt, c?.endedAt),
160
+ children: /* @__PURE__ */ r(w, {
161
+ ...k,
161
162
  segments: x.work,
162
163
  markTail: !1
163
164
  })
164
- }), /* @__PURE__ */ r(k, {
165
- ...h,
166
- segments: [x.answer],
167
- markTail: !0
165
+ }), /* @__PURE__ */ r(u, {
166
+ when: x.answer,
167
+ children: (A) => /* @__PURE__ */ r(w, {
168
+ ...k,
169
+ segments: [A],
170
+ markTail: !0
171
+ })
168
172
  })]
169
173
  })
170
174
  });
171
175
  });
172
176
  export {
173
- te as MessageAssistantBody
177
+ se as MessageAssistantBody
174
178
  };
175
179
  //# sourceMappingURL=MessageAssistantBody.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageAssistantBody.js","sources":["../../../../src/chat/Message/turn/MessageAssistantBody.tsx"],"sourcesContent":["'use client';\n\nimport { ChevronDown } from '@reforma/icons/8';\nimport { cn } from '@reforma/lib';\nimport { observer } from 'mobx-react-lite';\n\nimport { Button } from '../../../Button';\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n useCollapsible,\n} from '../../../Collapsible';\nimport { For } from '../../../For';\nimport { Show } from '../../../Show';\nimport { ConversationPendingLoader } from '../../Conversation/ConversationPendingLoader';\nimport { partsFromSegmentGroups, streamingPhaseActiveIndex } from '../normalize/normalizeMessageParts';\nimport { MessagePhaseSection } from '../segments';\nimport styles from './Message.module.css';\nimport { useMessageTurn } from './messageTurnContext';\nimport { splitFinishedWork, workedForLabel } from './workedCollapse';\n\nimport type { ReactNode } from 'react';\nimport type { MessageSegment } from '../normalize/normalizeMessageParts';\nimport type { ReformaUIMessagePart } from '../types';\nimport type { GetPhaseStats } from './messageTurnContext';\n\nfunction segmentsWithoutSources(segments: readonly MessageSegment[]): MessageSegment[] {\n const next: MessageSegment[] = [];\n\n for (const segment of segments) {\n const groups = segment.groups.filter(group => group.kind !== 'sources');\n\n if (groups.length > 0) {\n next.push({ ...segment, groups });\n }\n }\n\n return next;\n}\n\ntype SegmentListProps = {\n segments: readonly MessageSegment[];\n messageId: string;\n isStreaming: boolean;\n isLiveMessage: boolean;\n turnActive: boolean;\n phaseActiveIndex: number;\n getPhaseStats: GetPhaseStats | undefined;\n lastPart: ReformaUIMessagePart | undefined;\n loaderParts: readonly ReformaUIMessagePart[];\n /** Work under the spoiler is not the message tail, so its phases stay closed. */\n markTail: boolean;\n};\n\nfunction AssistantSegments({\n segments,\n messageId,\n isStreaming,\n isLiveMessage,\n turnActive,\n phaseActiveIndex,\n getPhaseStats,\n lastPart,\n loaderParts,\n markTail,\n}: SegmentListProps) {\n return (\n <For each={ segments }>\n { (segment, segIndex, { isLast }) => {\n const isLastSegment = markTail && isLast;\n\n return (\n <MessagePhaseSection\n key={ `${ messageId }-${ segment.index }` }\n segment={ segment }\n messageId={ messageId }\n isStreaming={ isStreaming }\n isLiveMessage={ isLiveMessage }\n isLastSegment={ isLastSegment }\n streamActive={ turnActive && (isLastSegment || segIndex === phaseActiveIndex) }\n fileStats={\n segment.layout === 'grouped'\n ? getPhaseStats?.(partsFromSegmentGroups(segment.groups))\n : undefined\n }\n >\n { isLastSegment && isStreaming\n ? (\n <ConversationPendingLoader\n lastPart={ lastPart }\n messageId={ messageId }\n parts={ loaderParts }\n />\n )\n : null }\n </MessagePhaseSection>\n );\n } }\n </For>\n );\n}\n\nfunction WorkedTrigger({ label }: { label: string }) {\n const { state } = useCollapsible();\n\n return (\n <CollapsibleTrigger asChild>\n <Button\n type=\"button\"\n variant=\"inline\"\n color=\"secondary\"\n className={ styles.workedTrigger }\n >\n { label }\n <ChevronDown\n className={ cn('chevron', 'next') }\n aria-expanded={ state.isExpanded }\n aria-hidden\n />\n </Button>\n </CollapsibleTrigger>\n );\n}\n\n/** Closed panel stays out of the DOM. `hidden=until-found` is still a flex item and keeps `.worked`'s gap. */\nfunction WorkedPanel({ children }: { children: ReactNode }) {\n const { state } = useCollapsible();\n\n return (\n <Show when={ state.isExpanded }>\n <CollapsibleContent className={ styles.workedPanel }>\n { children }\n </CollapsibleContent>\n </Show>\n );\n}\n\nfunction WorkedFor({ label, children }: { label: string; children: ReactNode }) {\n return (\n <Collapsible className={ styles.worked } defaultOpen={ false }>\n <WorkedTrigger label={ label } />\n <WorkedPanel>{ children }</WorkedPanel>\n </Collapsible>\n );\n}\n\n/**\n * Assistant turn segments and streaming pending loader.\n * A finished text answer folds the work into one \"Worked for …\" disclosure.\n * Cancelled turns and turns that do not end on text keep the phase rows open.\n */\nexport const MessageAssistantBody = observer(({\n hideSources = false,\n}: {\n /** Editor footer owns citations — drop in-body Sources groups. */\n hideSources?: boolean;\n} = {}) => {\n const turn = useMessageTurn();\n\n if (turn?.role !== 'assistant' || turn.message.role !== 'assistant') {\n return null;\n }\n\n const {\n messageId,\n segments: rawSegments,\n lastPart,\n turnActive,\n isStreaming,\n isLastMessage,\n getPhaseStats,\n } = turn;\n const segments = hideSources ? segmentsWithoutSources(rawSegments) : rawSegments;\n const loaderParts = turn.message.parts;\n const metadata = turn.message.metadata;\n\n if (segments.length === 0 && !isStreaming) {\n return null;\n }\n\n const phaseActiveIndex = streamingPhaseActiveIndex(segments, isStreaming);\n const finished = splitFinishedWork(segments, {\n streaming: isStreaming,\n cancelled: metadata?.stopReason === 'cancelled',\n });\n const listProps = {\n messageId,\n isStreaming,\n isLiveMessage: isLastMessage,\n turnActive,\n phaseActiveIndex,\n getPhaseStats,\n lastPart,\n loaderParts,\n };\n\n return (\n <Show\n when={ finished }\n fallback={ (\n <>\n <AssistantSegments\n { ...listProps }\n segments={ segments }\n markTail\n />\n <Show when={ isStreaming && segments.length === 0 }>\n <ConversationPendingLoader\n lastPart={ lastPart }\n messageId={ messageId }\n parts={ loaderParts }\n />\n </Show>\n </>\n ) }\n >\n { split => (\n <>\n <WorkedFor label={ workedForLabel(metadata?.startedAt, metadata?.endedAt) }>\n <AssistantSegments\n { ...listProps }\n segments={ split.work }\n markTail={ false }\n />\n </WorkedFor>\n <AssistantSegments\n { ...listProps }\n segments={ [split.answer] }\n markTail\n />\n </>\n ) }\n </Show>\n );\n});\n"],"names":["segmentsWithoutSources","segments","next","segment","groups","group","AssistantSegments","messageId","isStreaming","isLiveMessage","turnActive","phaseActiveIndex","getPhaseStats","lastPart","loaderParts","markTail","For","segIndex","isLast","isLastSegment","MessagePhaseSection","partsFromSegmentGroups","_jsx","ConversationPendingLoader","WorkedTrigger","label","state","useCollapsible","CollapsibleTrigger","Button","styles","ChevronDown","cn","WorkedPanel","children","Show","CollapsibleContent","WorkedFor","Collapsible","MessageAssistantBody","observer","hideSources","turn","useMessageTurn","rawSegments","isLastMessage","metadata","streamingPhaseActiveIndex","finished","splitFinishedWork","listProps","_Fragment","split","_jsxs","workedForLabel"],"mappings":"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"}
1
+ {"version":3,"file":"MessageAssistantBody.js","sources":["../../../../src/chat/Message/turn/MessageAssistantBody.tsx"],"sourcesContent":["'use client';\n\nimport { ChevronDown } from '@reforma/icons/8';\nimport { cn } from '@reforma/lib';\nimport { observer } from 'mobx-react-lite';\n\nimport { Button } from '../../../Button';\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n useCollapsible,\n} from '../../../Collapsible';\nimport { For } from '../../../For';\nimport { Show } from '../../../Show';\nimport { ConversationPendingLoader } from '../../Conversation/ConversationPendingLoader';\nimport { partsFromSegmentGroups, streamingPhaseActiveIndex } from '../normalize/normalizeMessageParts';\nimport { MessagePhaseSection } from '../segments';\nimport styles from './Message.module.css';\nimport { useMessageTurn } from './messageTurnContext';\nimport { splitFinishedWork, workedForLabel } from './workedCollapse';\n\nimport type { ReactNode } from 'react';\nimport type { MessageSegment } from '../normalize/normalizeMessageParts';\nimport type { ReformaUIMessagePart } from '../types';\nimport type { GetPhaseStats } from './messageTurnContext';\n\nfunction segmentsWithoutSources(segments: readonly MessageSegment[]): MessageSegment[] {\n const next: MessageSegment[] = [];\n\n for (const segment of segments) {\n const groups = segment.groups.filter(group => group.kind !== 'sources');\n\n if (groups.length > 0) {\n next.push({ ...segment, groups });\n }\n }\n\n return next;\n}\n\ntype SegmentListProps = {\n segments: readonly MessageSegment[];\n messageId: string;\n isStreaming: boolean;\n isLiveMessage: boolean;\n turnActive: boolean;\n phaseActiveIndex: number;\n getPhaseStats: GetPhaseStats | undefined;\n lastPart: ReformaUIMessagePart | undefined;\n loaderParts: readonly ReformaUIMessagePart[];\n /** Work under the spoiler is not the message tail, so its phases stay closed. */\n markTail: boolean;\n};\n\nfunction AssistantSegments({\n segments,\n messageId,\n isStreaming,\n isLiveMessage,\n turnActive,\n phaseActiveIndex,\n getPhaseStats,\n lastPart,\n loaderParts,\n markTail,\n}: SegmentListProps) {\n return (\n <For each={ segments }>\n { (segment, segIndex, { isLast }) => {\n const isLastSegment = markTail && isLast;\n\n return (\n <MessagePhaseSection\n key={ `${ messageId }-${ segment.index }` }\n segment={ segment }\n messageId={ messageId }\n isStreaming={ isStreaming }\n isLiveMessage={ isLiveMessage }\n isLastSegment={ isLastSegment }\n streamActive={ turnActive && (isLastSegment || segIndex === phaseActiveIndex) }\n fileStats={\n segment.layout === 'grouped'\n ? getPhaseStats?.(partsFromSegmentGroups(segment.groups))\n : undefined\n }\n >\n { isLastSegment && isStreaming\n ? (\n <ConversationPendingLoader\n lastPart={ lastPart }\n messageId={ messageId }\n parts={ loaderParts }\n />\n )\n : null }\n </MessagePhaseSection>\n );\n } }\n </For>\n );\n}\n\nfunction WorkedTrigger({ label }: { label: string }) {\n const { state } = useCollapsible();\n\n return (\n <CollapsibleTrigger asChild>\n <Button\n type=\"button\"\n variant=\"inline\"\n color=\"secondary\"\n className={ styles.workedTrigger }\n >\n { label }\n <ChevronDown\n className={ cn('chevron', 'next') }\n aria-expanded={ state.isExpanded }\n aria-hidden\n />\n </Button>\n </CollapsibleTrigger>\n );\n}\n\n/** Closed panel stays out of the DOM. `hidden=until-found` is still a flex item and keeps `.worked`'s gap. */\nfunction WorkedPanel({ children }: { children: ReactNode }) {\n const { state } = useCollapsible();\n\n return (\n <Show when={ state.isExpanded }>\n <CollapsibleContent className={ styles.workedPanel }>\n { children }\n </CollapsibleContent>\n </Show>\n );\n}\n\nfunction WorkedFor({ label, children }: { label: string; children: ReactNode }) {\n return (\n <Collapsible className={ styles.worked } defaultOpen={ false }>\n <WorkedTrigger label={ label } />\n <WorkedPanel>{ children }</WorkedPanel>\n </Collapsible>\n );\n}\n\n/**\n * Assistant turn segments and streaming pending loader.\n * A finished text answer folds the work into one \"Worked for …\" disclosure.\n * The latest turn keeps its phase rows open when cancelled or not ending on text;\n * an older one folds them anyway.\n */\nexport const MessageAssistantBody = observer(({\n hideSources = false,\n}: {\n /** Editor footer owns citations — drop in-body Sources groups. */\n hideSources?: boolean;\n} = {}) => {\n const turn = useMessageTurn();\n\n if (turn?.role !== 'assistant' || turn.message.role !== 'assistant') {\n return null;\n }\n\n const {\n messageId,\n segments: rawSegments,\n lastPart,\n turnActive,\n isStreaming,\n isLastMessage,\n getPhaseStats,\n } = turn;\n const segments = hideSources ? segmentsWithoutSources(rawSegments) : rawSegments;\n const loaderParts = turn.message.parts;\n const metadata = turn.message.metadata;\n\n if (segments.length === 0 && !isStreaming) {\n return null;\n }\n\n const phaseActiveIndex = streamingPhaseActiveIndex(segments, isStreaming);\n const finished = splitFinishedWork(segments, {\n streaming: isStreaming,\n cancelled: metadata?.stopReason === 'cancelled',\n superseded: !isLastMessage,\n });\n const listProps = {\n messageId,\n isStreaming,\n isLiveMessage: isLastMessage,\n turnActive,\n phaseActiveIndex,\n getPhaseStats,\n lastPart,\n loaderParts,\n };\n\n return (\n <Show\n when={ finished }\n fallback={ (\n <>\n <AssistantSegments\n { ...listProps }\n segments={ segments }\n markTail\n />\n <Show when={ isStreaming && segments.length === 0 }>\n <ConversationPendingLoader\n lastPart={ lastPart }\n messageId={ messageId }\n parts={ loaderParts }\n />\n </Show>\n </>\n ) }\n >\n { split => (\n <>\n <WorkedFor label={ workedForLabel(metadata?.startedAt, metadata?.endedAt) }>\n <AssistantSegments\n { ...listProps }\n segments={ split.work }\n markTail={ false }\n />\n </WorkedFor>\n <Show when={ split.answer }>\n { answer => (\n <AssistantSegments\n { ...listProps }\n segments={ [answer] }\n markTail\n />\n ) }\n </Show>\n </>\n ) }\n </Show>\n );\n});\n"],"names":["segmentsWithoutSources","segments","next","segment","groups","group","AssistantSegments","messageId","isStreaming","isLiveMessage","turnActive","phaseActiveIndex","getPhaseStats","lastPart","loaderParts","markTail","For","segIndex","isLast","isLastSegment","MessagePhaseSection","partsFromSegmentGroups","_jsx","ConversationPendingLoader","WorkedTrigger","label","state","useCollapsible","CollapsibleTrigger","Button","styles","ChevronDown","cn","WorkedPanel","children","Show","CollapsibleContent","WorkedFor","Collapsible","MessageAssistantBody","observer","hideSources","turn","useMessageTurn","rawSegments","isLastMessage","metadata","streamingPhaseActiveIndex","finished","splitFinishedWork","listProps","_Fragment","split","_jsxs","workedForLabel","answer"],"mappings":"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"}
@@ -1,15 +1,19 @@
1
1
  import type { MessageSegment } from '../normalize/normalizeMessageParts';
2
2
  export type FinishedWorkSplit = {
3
3
  work: readonly MessageSegment[];
4
- answer: MessageSegment;
4
+ /** Null when a superseded turn has no text answer: everything folds. */
5
+ answer: MessageSegment | null;
5
6
  };
6
7
  /**
7
8
  * Finished turn whose last visible part is text: tuck every segment before that
8
- * answer under one disclosure. Streaming, cancelled, and "still waiting" turns stay open.
9
+ * answer under one disclosure. Streaming and "still waiting" turns stay open.
10
+ * The latest turn also stays open when cancelled or not ending on text; once a
11
+ * later message supersedes it, its work folds anyway.
9
12
  */
10
13
  export declare function splitFinishedWork(segments: readonly MessageSegment[], flags: {
11
14
  streaming: boolean;
12
15
  cancelled: boolean;
16
+ superseded: boolean;
13
17
  }): FinishedWorkSplit | null;
14
18
  /** "Worked for 25s" / "Worked for 2m". "Worked" when the turn has no timestamps. */
15
19
  export declare function workedForLabel(startedAt: number | undefined, endedAt: number | undefined): string;
@@ -1 +1 @@
1
- {"version":3,"file":"workedCollapse.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/turn/workedCollapse.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,MAAM,MAAM,iBAAiB,GAAG;IAC5B,IAAI,EAAE,SAAS,cAAc,EAAE,CAAC;IAChC,MAAM,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,iBAAiB,CAC7B,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,KAAK,EAAE;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GAClD,iBAAiB,GAAG,IAAI,CAyB1B;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAgCjG"}
1
+ {"version":3,"file":"workedCollapse.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/turn/workedCollapse.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,MAAM,MAAM,iBAAiB,GAAG;IAC5B,IAAI,EAAE,SAAS,cAAc,EAAE,CAAC;IAChC,wEAAwE;IACxE,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;CACjC,CAAC;AAYF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC7B,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,KAAK,EAAE;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,GACvE,iBAAiB,GAAG,IAAI,CAgB1B;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAgCjG"}
@@ -1,31 +1,37 @@
1
1
  import { isTextUIPart as l } from "@reforma/types";
2
2
  import { segmentRequiresUserAction as s, lastVisiblePartFromGroups as f } from "../normalize/normalizeMessageParts.js";
3
- function a(r, e) {
4
- if (e.streaming || e.cancelled || r.length < 2 || r.some((i) => s(i.groups)))
5
- return null;
6
- const n = r[r.length - 1];
7
- if (!n || n.layout !== "ungrouped")
3
+ function c(r) {
4
+ if (!r || r.layout !== "ungrouped")
5
+ return !1;
6
+ const o = f(r.groups);
7
+ return !!o && l(o) && o.state !== "streaming" && !!o.text.trim();
8
+ }
9
+ function h(r, o) {
10
+ if (o.streaming || o.cancelled && !o.superseded || r.some((e) => s(e.groups)))
8
11
  return null;
9
- const o = f(n.groups);
10
- return !o || !l(o) || o.state === "streaming" || !o.text.trim() ? null : {
12
+ const n = r.at(-1);
13
+ return c(n) ? r.length < 2 ? null : {
11
14
  work: r.slice(0, -1),
12
15
  answer: n
13
- };
16
+ } : o.superseded && r.length > 0 ? {
17
+ work: r,
18
+ answer: null
19
+ } : null;
14
20
  }
15
- function h(r, e) {
16
- if (r == null || e == null || !Number.isFinite(r) || !Number.isFinite(e) || e < r)
21
+ function k(r, o) {
22
+ if (r == null || o == null || !Number.isFinite(r) || !Number.isFinite(o) || o < r)
17
23
  return "Worked";
18
- const n = Math.max(1, Math.round((e - r) / 1e3));
24
+ const n = Math.max(1, Math.round((o - r) / 1e3));
19
25
  if (n < 60)
20
26
  return `Worked for ${n}s`;
21
- const o = Math.floor(n / 60), i = n % 60;
22
- if (o < 60)
23
- return i === 0 ? `Worked for ${o}m` : `Worked for ${o}m ${i}s`;
24
- const t = Math.floor(o / 60), u = o % 60;
25
- return u === 0 ? `Worked for ${t}h` : `Worked for ${t}h ${u}m`;
27
+ const e = Math.floor(n / 60), u = n % 60;
28
+ if (e < 60)
29
+ return u === 0 ? `Worked for ${e}m` : `Worked for ${e}m ${u}s`;
30
+ const i = Math.floor(e / 60), t = e % 60;
31
+ return t === 0 ? `Worked for ${i}h` : `Worked for ${i}h ${t}m`;
26
32
  }
27
33
  export {
28
- a as splitFinishedWork,
29
- h as workedForLabel
34
+ h as splitFinishedWork,
35
+ k as workedForLabel
30
36
  };
31
37
  //# sourceMappingURL=workedCollapse.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"workedCollapse.js","sources":["../../../../src/chat/Message/turn/workedCollapse.ts"],"sourcesContent":["import { isTextUIPart } from '@reforma/types';\n\nimport {\n lastVisiblePartFromGroups,\n segmentRequiresUserAction,\n} from '../normalize/normalizeMessageParts';\n\nimport type { MessageSegment } from '../normalize/normalizeMessageParts';\n\nexport type FinishedWorkSplit = {\n work: readonly MessageSegment[];\n answer: MessageSegment;\n};\n\n/**\n * Finished turn whose last visible part is text: tuck every segment before that\n * answer under one disclosure. Streaming, cancelled, and \"still waiting\" turns stay open.\n */\nexport function splitFinishedWork(\n segments: readonly MessageSegment[],\n flags: { streaming: boolean; cancelled: boolean }\n): FinishedWorkSplit | null {\n if (flags.streaming || flags.cancelled || segments.length < 2) {\n return null;\n }\n\n if (segments.some(segment => segmentRequiresUserAction(segment.groups))) {\n return null;\n }\n\n const answer = segments[segments.length - 1];\n\n if (!answer || answer.layout !== 'ungrouped') {\n return null;\n }\n\n const tail = lastVisiblePartFromGroups(answer.groups);\n\n if (!tail || !isTextUIPart(tail) || tail.state === 'streaming' || !tail.text.trim()) {\n return null;\n }\n\n return {\n work: segments.slice(0, -1),\n answer,\n };\n}\n\n/** \"Worked for 25s\" / \"Worked for 2m\". \"Worked\" when the turn has no timestamps. */\nexport function workedForLabel(startedAt: number | undefined, endedAt: number | undefined): string {\n if (\n startedAt == null\n || endedAt == null\n || !Number.isFinite(startedAt)\n || !Number.isFinite(endedAt)\n || endedAt < startedAt\n ) {\n return 'Worked';\n }\n\n const seconds = Math.max(1, Math.round((endedAt - startedAt) / 1000));\n\n if (seconds < 60) {\n return `Worked for ${ seconds }s`;\n }\n\n const minutes = Math.floor(seconds / 60);\n const remSeconds = seconds % 60;\n\n if (minutes < 60) {\n return remSeconds === 0\n ? `Worked for ${ minutes }m`\n : `Worked for ${ minutes }m ${ remSeconds }s`;\n }\n\n const hours = Math.floor(minutes / 60);\n const remMinutes = minutes % 60;\n\n return remMinutes === 0\n ? `Worked for ${ hours }h`\n : `Worked for ${ hours }h ${ remMinutes }m`;\n}\n"],"names":["splitFinishedWork","segments","flags","segment","segmentRequiresUserAction","answer","tail","lastVisiblePartFromGroups","isTextUIPart","workedForLabel","startedAt","endedAt","seconds","minutes","remSeconds","hours","remMinutes"],"mappings":";;AAMO,SAASA,EAAkBC,GAAUC,GAAO;AAIjD,MAHIA,EAAM,aAAaA,EAAM,aAAaD,EAAS,SAAS,KAGxDA,EAAS,KAAK,CAAAE,MAAWC,EAA0BD,EAAQ,MAAM,CAAC;AACpE,WAAO;AAET,QAAME,IAASJ,EAASA,EAAS,SAAS,CAAC;AAC3C,MAAI,CAACI,KAAUA,EAAO,WAAW;AAC/B,WAAO;AAET,QAAMC,IAAOC,EAA0BF,EAAO,MAAM;AACpD,SAAI,CAACC,KAAQ,CAACE,EAAaF,CAAI,KAAKA,EAAK,UAAU,eAAe,CAACA,EAAK,KAAK,SACpE,OAEF;AAAA,IACL,MAAML,EAAS,MAAM,GAAG,EAAE;AAAA,IAC1B,QAAAI;AAAA,EAAA;AAEJ;AAGO,SAASI,EAAeC,GAAWC,GAAS;AACjD,MAAID,KAAa,QAAQC,KAAW,QAAQ,CAAC,OAAO,SAASD,CAAS,KAAK,CAAC,OAAO,SAASC,CAAO,KAAKA,IAAUD;AAChH,WAAO;AAET,QAAME,IAAU,KAAK,IAAI,GAAG,KAAK,OAAOD,IAAUD,KAAa,GAAI,CAAC;AACpE,MAAIE,IAAU;AACZ,WAAO,cAAcA,CAAO;AAE9B,QAAMC,IAAU,KAAK,MAAMD,IAAU,EAAE,GACjCE,IAAaF,IAAU;AAC7B,MAAIC,IAAU;AACZ,WAAOC,MAAe,IAAI,cAAcD,CAAO,MAAM,cAAcA,CAAO,KAAKC,CAAU;AAE3F,QAAMC,IAAQ,KAAK,MAAMF,IAAU,EAAE,GAC/BG,IAAaH,IAAU;AAC7B,SAAOG,MAAe,IAAI,cAAcD,CAAK,MAAM,cAAcA,CAAK,KAAKC,CAAU;AACvF;"}
1
+ {"version":3,"file":"workedCollapse.js","sources":["../../../../src/chat/Message/turn/workedCollapse.ts"],"sourcesContent":["import { isTextUIPart } from '@reforma/types';\n\nimport {\n lastVisiblePartFromGroups,\n segmentRequiresUserAction,\n} from '../normalize/normalizeMessageParts';\n\nimport type { MessageSegment } from '../normalize/normalizeMessageParts';\n\nexport type FinishedWorkSplit = {\n work: readonly MessageSegment[];\n /** Null when a superseded turn has no text answer: everything folds. */\n answer: MessageSegment | null;\n};\n\nfunction isTextAnswer(segment: MessageSegment | undefined): segment is MessageSegment {\n if (!segment || segment.layout !== 'ungrouped') {\n return false;\n }\n\n const tail = lastVisiblePartFromGroups(segment.groups);\n\n return !!tail && isTextUIPart(tail) && tail.state !== 'streaming' && !!tail.text.trim();\n}\n\n/**\n * Finished turn whose last visible part is text: tuck every segment before that\n * answer under one disclosure. Streaming and \"still waiting\" turns stay open.\n * The latest turn also stays open when cancelled or not ending on text; once a\n * later message supersedes it, its work folds anyway.\n */\nexport function splitFinishedWork(\n segments: readonly MessageSegment[],\n flags: { streaming: boolean; cancelled: boolean; superseded: boolean }\n): FinishedWorkSplit | null {\n if (flags.streaming || (flags.cancelled && !flags.superseded)) {\n return null;\n }\n\n if (segments.some(segment => segmentRequiresUserAction(segment.groups))) {\n return null;\n }\n\n const answer = segments.at(-1);\n\n if (isTextAnswer(answer)) {\n return segments.length < 2 ? null : { work: segments.slice(0, -1), answer };\n }\n\n return flags.superseded && segments.length > 0 ? { work: segments, answer: null } : null;\n}\n\n/** \"Worked for 25s\" / \"Worked for 2m\". \"Worked\" when the turn has no timestamps. */\nexport function workedForLabel(startedAt: number | undefined, endedAt: number | undefined): string {\n if (\n startedAt == null\n || endedAt == null\n || !Number.isFinite(startedAt)\n || !Number.isFinite(endedAt)\n || endedAt < startedAt\n ) {\n return 'Worked';\n }\n\n const seconds = Math.max(1, Math.round((endedAt - startedAt) / 1000));\n\n if (seconds < 60) {\n return `Worked for ${ seconds }s`;\n }\n\n const minutes = Math.floor(seconds / 60);\n const remSeconds = seconds % 60;\n\n if (minutes < 60) {\n return remSeconds === 0\n ? `Worked for ${ minutes }m`\n : `Worked for ${ minutes }m ${ remSeconds }s`;\n }\n\n const hours = Math.floor(minutes / 60);\n const remMinutes = minutes % 60;\n\n return remMinutes === 0\n ? `Worked for ${ hours }h`\n : `Worked for ${ hours }h ${ remMinutes }m`;\n}\n"],"names":["isTextAnswer","segment","tail","lastVisiblePartFromGroups","isTextUIPart","splitFinishedWork","segments","flags","segmentRequiresUserAction","answer","workedForLabel","startedAt","endedAt","seconds","minutes","remSeconds","hours","remMinutes"],"mappings":";;AAEA,SAASA,EAAaC,GAAS;AAC7B,MAAI,CAACA,KAAWA,EAAQ,WAAW;AACjC,WAAO;AAET,QAAMC,IAAOC,EAA0BF,EAAQ,MAAM;AACrD,SAAO,CAAC,CAACC,KAAQE,EAAaF,CAAI,KAAKA,EAAK,UAAU,eAAe,CAAC,CAACA,EAAK,KAAK,KAAA;AACnF;AAQO,SAASG,EAAkBC,GAAUC,GAAO;AAIjD,MAHIA,EAAM,aAAaA,EAAM,aAAa,CAACA,EAAM,cAG7CD,EAAS,KAAK,CAAAL,MAAWO,EAA0BP,EAAQ,MAAM,CAAC;AACpE,WAAO;AAET,QAAMQ,IAASH,EAAS,GAAG,EAAE;AAC7B,SAAIN,EAAaS,CAAM,IACdH,EAAS,SAAS,IAAI,OAAO;AAAA,IAClC,MAAMA,EAAS,MAAM,GAAG,EAAE;AAAA,IAC1B,QAAAG;AAAA,EAAA,IAGGF,EAAM,cAAcD,EAAS,SAAS,IAAI;AAAA,IAC/C,MAAMA;AAAA,IACN,QAAQ;AAAA,EAAA,IACN;AACN;AAGO,SAASI,EAAeC,GAAWC,GAAS;AACjD,MAAID,KAAa,QAAQC,KAAW,QAAQ,CAAC,OAAO,SAASD,CAAS,KAAK,CAAC,OAAO,SAASC,CAAO,KAAKA,IAAUD;AAChH,WAAO;AAET,QAAME,IAAU,KAAK,IAAI,GAAG,KAAK,OAAOD,IAAUD,KAAa,GAAI,CAAC;AACpE,MAAIE,IAAU;AACZ,WAAO,cAAcA,CAAO;AAE9B,QAAMC,IAAU,KAAK,MAAMD,IAAU,EAAE,GACjCE,IAAaF,IAAU;AAC7B,MAAIC,IAAU;AACZ,WAAOC,MAAe,IAAI,cAAcD,CAAO,MAAM,cAAcA,CAAO,KAAKC,CAAU;AAE3F,QAAMC,IAAQ,KAAK,MAAMF,IAAU,EAAE,GAC/BG,IAAaH,IAAU;AAC7B,SAAOG,MAAe,IAAI,cAAcD,CAAK,MAAM,cAAcA,CAAK,KAAKC,CAAU;AACvF;"}
@@ -165,7 +165,7 @@ function ee({
165
165
  when: r,
166
166
  fallback: /* @__PURE__ */ o(m, {
167
167
  className: h.title,
168
- color: a ? "danger" : void 0,
168
+ color: a ? "secondary" : void 0,
169
169
  children: l
170
170
  }),
171
171
  children: /* @__PURE__ */ o(M, {
@@ -220,20 +220,20 @@ const Ce = U(({
220
220
  } = V(e.state, a);
221
221
  if (!B(e) || F(e) !== "Agent")
222
222
  return null;
223
- const u = W(e), s = e.state === "output-available" ? H(e.output) : void 0, f = u.useFailureLabel || !!s, v = R(e), A = p(v), L = e.state === "output-available" && !!e.output?.jobId, b = J(v, L), P = X(r), $ = Z({
223
+ const u = W(e), s = e.state === "output-available" ? H(e.output) : void 0, f = u.useFailureLabel || !!s, v = R(e), A = p(v), L = e.state === "output-available" && !!e.output?.jobId, y = J(v, L), P = X(r), $ = Z({
224
224
  live: c,
225
225
  failed: f,
226
226
  stalled: l,
227
227
  needsUser: a,
228
228
  activity: P
229
- }), y = i(e.output?.childThreadId) ?? i(r?.childThreadId), k = !!(y && n && !f), E = s ?? u.problemText ?? u.tooltip;
229
+ }), b = i(e.output?.childThreadId) ?? i(r?.childThreadId), k = !!(b && n && !f), E = s ?? u.problemText ?? u.tooltip;
230
230
  return /* @__PURE__ */ o(ee, {
231
231
  activity: $,
232
232
  errorText: E,
233
- onOpen: k ? () => n?.(y, A) : void 0,
233
+ onOpen: k ? () => n?.(b, A) : void 0,
234
234
  running: c && !f && !l,
235
235
  stalled: l,
236
- title: c && !f && !l ? b.live : b.done
236
+ title: c && !f && !l ? y.live : y.done
237
237
  });
238
238
  });
239
239
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"AgentTool.js","sources":["../../../../src/chat/Tool/agent/AgentTool.tsx"],"sourcesContent":["import { Message } from '@reforma/icons/14';\nimport { ProgressLoader } from '@reforma/icons/assets';\nimport { basename, humanizeString, plural } from '@reforma/lib';\nimport { getToolName, isToolUIPart } from '@reforma/types';\nimport { observer } from 'mobx-react-lite';\n\nimport { Box } from '../../../Box';\nimport { Pressable } from '../../../Pressable';\nimport { Shimmer } from '../../../Shimmer';\nimport { Show } from '../../../Show';\nimport { Text } from '../../../Text';\nimport { useChat } from '../../ChatContext';\nimport { useMessageTurn } from '../../Message/turn/messageTurnContext';\nimport { getToolFailureRowState, TOOL_INTERRUPTED_MESSAGE } from '../helpers';\nimport { ToolShellCard } from '../shell';\nimport { useToolProgress } from '../shell/toolProgress';\nimport shellStyles from '../shell/ToolShellCard.module.css';\nimport styles from './AgentTool.module.css';\n\nimport type { AgentToolInput, AgentToolOutput } from '@reforma/types/sandbox';\nimport type { ToolRendererProps } from '../types';\n\n/** User-facing labels for known subagent ids (fallback: capitalized id). */\nconst SUBAGENT_LABELS: Record<string, string> = {\n research: 'Explore',\n shell: 'Shell',\n verify: 'Verify',\n plan: 'Plan',\n};\n\nconst SUBAGENT_LIVE: Record<string, string> = {\n research: 'Exploring',\n shell: 'Running',\n verify: 'Verifying',\n plan: 'Planning',\n};\n\nfunction agentErrorFromOutput(output: unknown): string | undefined {\n if (output == null || typeof output !== 'object') {\n return undefined;\n }\n\n const error = (output as AgentToolOutput).error;\n\n return (typeof error === 'string' && error.trim().length > 0) ? error.trim() : undefined;\n}\n\nfunction agentNameFromPart(part: { input?: unknown; output?: unknown }): string | undefined {\n for (const source of [part.output, part.input]) {\n if (source == null || typeof source !== 'object') {\n continue;\n }\n\n const name = (source as AgentToolInput | AgentToolOutput).name;\n\n if (typeof name === 'string' && name.trim().length > 0) {\n return name.trim();\n }\n }\n\n return undefined;\n}\n\nfunction subagentLabel(name: string | undefined): string {\n const id = name?.trim() || 'research';\n const mapped = SUBAGENT_LABELS[id];\n\n if (mapped) {\n return mapped;\n }\n\n return id.charAt(0).toUpperCase() + id.slice(1);\n}\n\nfunction agentPhaseCopy(name: string | undefined, background: boolean): { live: string; done: string } {\n const id = name?.trim() || 'research';\n const label = subagentLabel(name);\n\n return {\n live: SUBAGENT_LIVE[id] ?? `Running ${ label }`,\n done: background ? `Started ${ label } agent in background` : `Ran ${ label } agent`,\n };\n}\n\nfunction fieldString(value: unknown): string | undefined {\n if (typeof value !== 'string') {\n return undefined;\n }\n\n const trimmed = value.trim();\n\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction fileLabel(input: Record<string, unknown>): string | undefined {\n const path = fieldString(input.path);\n\n if (path) {\n return basename(path);\n }\n\n if (!Array.isArray(input.paths)) {\n return undefined;\n }\n\n const files = input.paths.filter((item): item is string => typeof item === 'string' && item.trim().length > 0);\n\n if (files.length === 1) {\n return basename(files[0]);\n }\n\n if (files.length > 1) {\n return plural(files.length, 'file', 'files');\n }\n\n return undefined;\n}\n\nfunction fileActivity(verb: string, fallback: string) {\n return (input: Record<string, unknown>) => `${ verb } ${ fileLabel(input) ?? fallback }`;\n}\n\nconst TOOL_ACTIVITY: Record<string, (input: Record<string, unknown>) => string | undefined> = {\n Read: fileActivity('Reading', 'file'),\n Write: fileActivity('Writing', 'file'),\n Edit: fileActivity('Editing', 'file'),\n ListDirectory: fileActivity('Listing', 'files'),\n CreateDirectory: fileActivity('Creating', 'folder'),\n MoveFile: fileActivity('Moving', 'file'),\n RemoveFile: fileActivity('Removing', 'file'),\n Grep: input => `Grepping ${ fieldString(input.pattern) ?? 'code' }`,\n Glob: input => `Finding ${ fieldString(input.glob) ?? 'files' }`,\n GetBackgroundResult: () => 'Background task',\n Bash: (input) => {\n const command = fieldString(input.command);\n\n return command ? `Running ${ command }` : 'Running command';\n },\n Fetch: input => `Fetching ${ fieldString(input.url) ?? 'page' }`,\n Skill: input => `Loading ${ fieldString(input.name) ?? 'skill' }`,\n GetMcpResources: (input) => {\n const uri = fieldString(input.uri);\n\n if (uri) {\n const tail = uri.replace(/\\/+$/, '').split('/').pop()?.trim();\n\n return `Reading ${ tail || uri }`;\n }\n\n return 'Listing MCP resources';\n },\n Preamble: input => fieldString(input.content),\n ReadLints: () => 'Checking lints',\n PageScreenshot: () => 'Capturing screenshot',\n CheckPage: () => 'Checking pages',\n DevServerStatus: () => 'Checking project',\n ImportAsset: () => 'Importing asset',\n CreatePlan: () => 'Creating plan',\n EditPlan: () => 'Editing plan',\n ReadPlan: () => 'Reading plan',\n};\n\n/** One composer strip: who is running, and the child thread Show opens. */\nexport function subagentComposerCopy(\n part: { input?: unknown; output?: unknown },\n patch: Record<string, unknown> | undefined\n): { text: string; label: string; childThreadId?: string; waiting: boolean } {\n const name = agentNameFromPart(part);\n const label = subagentLabel(name);\n const waiting = patch?.needsUser === true;\n const childThreadId = fieldString((part.output as AgentToolOutput | undefined)?.childThreadId)\n ?? fieldString(patch?.childThreadId);\n const text = waiting\n ? `${ label } · Waiting for you`\n : `${ label } Agent working`;\n\n return { text, label, childThreadId, waiting };\n}\n\n/** Live subtitle for a tool — same copy for Agent rows and the compact rail task. */\nexport function subagentActivityLabel(patch: Record<string, unknown> | undefined): string | undefined {\n if (!patch) {\n return undefined;\n }\n\n if (patch.type === 'text') {\n return 'Finishing reply';\n }\n\n if (patch.type === 'reasoning') {\n return 'Thinking…';\n }\n\n const toolName = fieldString(patch.toolName);\n\n if (!toolName) {\n return undefined;\n }\n\n const rawInput = patch.input;\n const input = (rawInput != null && typeof rawInput === 'object' && !Array.isArray(rawInput))\n ? rawInput as Record<string, unknown>\n : {};\n\n return TOOL_ACTIVITY[toolName]?.(input)\n ?? `Using ${ fieldString(patch.title) ?? humanizeString(toolName) }`;\n}\n\n/** Live/waiting subtitle. Done rows stay quiet — no empty \"Completed\". */\nexport function agentStatusLine(input: {\n live: boolean;\n failed: boolean;\n stalled?: boolean;\n needsUser?: boolean;\n activity?: string;\n}): string | undefined {\n if (input.failed || input.stalled) {\n return undefined;\n }\n\n if (input.needsUser) {\n return 'Waiting for you';\n }\n\n if (!input.live) {\n return undefined;\n }\n\n return input.activity ?? 'Starting…';\n}\n\n/** Subagent card. Running: loader, shimmer title, gray activity. Finished: same frame, quiet title. */\nfunction AgentCard({\n title,\n activity,\n errorText,\n running,\n stalled,\n onOpen,\n}: {\n title: string;\n activity?: string;\n errorText?: string;\n running: boolean;\n stalled: boolean;\n onOpen?: () => void;\n}) {\n const heading = stalled ? TOOL_INTERRUPTED_MESSAGE : title;\n const copy = (\n <Box align=\"center\" direction=\"row\" fullWidth gap=\"md\" padding=\"md\">\n <Show\n when={ running }\n fallback={ <Message aria-hidden /> }\n >\n <ProgressLoader aria-hidden size={ 14 } />\n </Show>\n <Box gap=\"xxs\" grow>\n <Show\n when={ running }\n fallback={ (\n <Text className={ styles.title } color={ stalled ? 'danger' : undefined }>\n { heading }\n </Text>\n ) }\n >\n <Shimmer as=\"span\" className={ styles.title } duration={ 1 }>\n { heading }\n </Shimmer>\n </Show>\n <Show when={ running ? activity : undefined }>\n { line => (\n <Text color=\"secondary\" truncate variant=\"sm\">\n { line }\n </Text>\n ) }\n </Show>\n <Show when={ errorText }>\n { line => (\n <Text color=\"danger\" variant=\"xs\">{ line }</Text>\n ) }\n </Show>\n </Box>\n </Box>\n );\n\n return (\n <ToolShellCard\n aria-busy={ running || undefined }\n className={ shellStyles.tool }\n collapsible={ false }\n data-slot=\"agent-tool\"\n >\n <Show\n when={ onOpen }\n fallback={ copy }\n >\n { open => (\n <Pressable\n aria-label={ activity ? `${ heading }. ${ activity }` : heading }\n className={ styles.hit }\n onPress={ open }\n >\n { copy }\n </Pressable>\n ) }\n </Show>\n </ToolShellCard>\n );\n}\n\n/** Agent subagent card. Opens the child thread. */\nexport const AgentTool = observer(({ part }: ToolRendererProps) => {\n const turn = useMessageTurn();\n const { onOpenSubagent } = useChat();\n const patch = turn?.getToolMeta?.(part.toolCallId)?.patch;\n const needsUser = patch?.needsUser === true;\n const { live, stalled } = useToolProgress(part.state, needsUser);\n\n if (!isToolUIPart(part) || getToolName(part) !== 'Agent') {\n return null;\n }\n\n const failure = getToolFailureRowState(part);\n const logicalError = part.state === 'output-available'\n ? agentErrorFromOutput(part.output)\n : undefined;\n const failed = failure.useFailureLabel || Boolean(logicalError);\n const agentName = agentNameFromPart(part);\n const label = subagentLabel(agentName);\n const background = part.state === 'output-available' && Boolean((part.output as AgentToolOutput | undefined)?.jobId);\n const phase = agentPhaseCopy(agentName, background);\n const activity = subagentActivityLabel(patch);\n const statusLine = agentStatusLine({\n live,\n failed,\n stalled,\n needsUser,\n activity,\n });\n const childThreadId = fieldString((part.output as AgentToolOutput | undefined)?.childThreadId)\n ?? fieldString(patch?.childThreadId);\n const canOpen = Boolean(childThreadId && onOpenSubagent && !failed);\n const errorText = logicalError ?? failure.problemText ?? failure.tooltip;\n const openChild = canOpen\n ? () => onOpenSubagent?.(childThreadId!, label)\n : undefined;\n\n return (\n <AgentCard\n activity={ statusLine }\n errorText={ errorText }\n onOpen={ openChild }\n running={ live && !failed && !stalled }\n stalled={ stalled }\n title={ live && !failed && !stalled ? phase.live : phase.done }\n />\n );\n});\n"],"names":["SUBAGENT_LABELS","SUBAGENT_LIVE","agentErrorFromOutput","output","error","agentNameFromPart","part","source","name","subagentLabel","id","mapped","agentPhaseCopy","background","label","fieldString","value","trimmed","fileLabel","input","path","basename","files","item","plural","fileActivity","verb","fallback","TOOL_ACTIVITY","command","uri","subagentComposerCopy","patch","waiting","childThreadId","subagentActivityLabel","toolName","rawInput","humanizeString","agentStatusLine","AgentCard","title","activity","errorText","running","stalled","onOpen","heading","TOOL_INTERRUPTED_MESSAGE","copy","Box","_jsx","Show","Message","ProgressLoader","_jsxs","Text","styles","Shimmer","line","ToolShellCard","shellStyles","open","Pressable","AgentTool","observer","turn","useMessageTurn","onOpenSubagent","useChat","needsUser","live","useToolProgress","isToolUIPart","getToolName","failure","getToolFailureRowState","logicalError","failed","agentName","phase","statusLine","canOpen"],"mappings":"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"}
1
+ {"version":3,"file":"AgentTool.js","sources":["../../../../src/chat/Tool/agent/AgentTool.tsx"],"sourcesContent":["import { Message } from '@reforma/icons/14';\nimport { ProgressLoader } from '@reforma/icons/assets';\nimport { basename, humanizeString, plural } from '@reforma/lib';\nimport { getToolName, isToolUIPart } from '@reforma/types';\nimport { observer } from 'mobx-react-lite';\n\nimport { Box } from '../../../Box';\nimport { Pressable } from '../../../Pressable';\nimport { Shimmer } from '../../../Shimmer';\nimport { Show } from '../../../Show';\nimport { Text } from '../../../Text';\nimport { useChat } from '../../ChatContext';\nimport { useMessageTurn } from '../../Message/turn/messageTurnContext';\nimport { getToolFailureRowState, TOOL_INTERRUPTED_MESSAGE } from '../helpers';\nimport { ToolShellCard } from '../shell';\nimport { useToolProgress } from '../shell/toolProgress';\nimport shellStyles from '../shell/ToolShellCard.module.css';\nimport styles from './AgentTool.module.css';\n\nimport type { AgentToolInput, AgentToolOutput } from '@reforma/types/sandbox';\nimport type { ToolRendererProps } from '../types';\n\n/** User-facing labels for known subagent ids (fallback: capitalized id). */\nconst SUBAGENT_LABELS: Record<string, string> = {\n research: 'Explore',\n shell: 'Shell',\n verify: 'Verify',\n plan: 'Plan',\n};\n\nconst SUBAGENT_LIVE: Record<string, string> = {\n research: 'Exploring',\n shell: 'Running',\n verify: 'Verifying',\n plan: 'Planning',\n};\n\nfunction agentErrorFromOutput(output: unknown): string | undefined {\n if (output == null || typeof output !== 'object') {\n return undefined;\n }\n\n const error = (output as AgentToolOutput).error;\n\n return (typeof error === 'string' && error.trim().length > 0) ? error.trim() : undefined;\n}\n\nfunction agentNameFromPart(part: { input?: unknown; output?: unknown }): string | undefined {\n for (const source of [part.output, part.input]) {\n if (source == null || typeof source !== 'object') {\n continue;\n }\n\n const name = (source as AgentToolInput | AgentToolOutput).name;\n\n if (typeof name === 'string' && name.trim().length > 0) {\n return name.trim();\n }\n }\n\n return undefined;\n}\n\nfunction subagentLabel(name: string | undefined): string {\n const id = name?.trim() || 'research';\n const mapped = SUBAGENT_LABELS[id];\n\n if (mapped) {\n return mapped;\n }\n\n return id.charAt(0).toUpperCase() + id.slice(1);\n}\n\nfunction agentPhaseCopy(name: string | undefined, background: boolean): { live: string; done: string } {\n const id = name?.trim() || 'research';\n const label = subagentLabel(name);\n\n return {\n live: SUBAGENT_LIVE[id] ?? `Running ${ label }`,\n done: background ? `Started ${ label } agent in background` : `Ran ${ label } agent`,\n };\n}\n\nfunction fieldString(value: unknown): string | undefined {\n if (typeof value !== 'string') {\n return undefined;\n }\n\n const trimmed = value.trim();\n\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction fileLabel(input: Record<string, unknown>): string | undefined {\n const path = fieldString(input.path);\n\n if (path) {\n return basename(path);\n }\n\n if (!Array.isArray(input.paths)) {\n return undefined;\n }\n\n const files = input.paths.filter((item): item is string => typeof item === 'string' && item.trim().length > 0);\n\n if (files.length === 1) {\n return basename(files[0]);\n }\n\n if (files.length > 1) {\n return plural(files.length, 'file', 'files');\n }\n\n return undefined;\n}\n\nfunction fileActivity(verb: string, fallback: string) {\n return (input: Record<string, unknown>) => `${ verb } ${ fileLabel(input) ?? fallback }`;\n}\n\nconst TOOL_ACTIVITY: Record<string, (input: Record<string, unknown>) => string | undefined> = {\n Read: fileActivity('Reading', 'file'),\n Write: fileActivity('Writing', 'file'),\n Edit: fileActivity('Editing', 'file'),\n ListDirectory: fileActivity('Listing', 'files'),\n CreateDirectory: fileActivity('Creating', 'folder'),\n MoveFile: fileActivity('Moving', 'file'),\n RemoveFile: fileActivity('Removing', 'file'),\n Grep: input => `Grepping ${ fieldString(input.pattern) ?? 'code' }`,\n Glob: input => `Finding ${ fieldString(input.glob) ?? 'files' }`,\n GetBackgroundResult: () => 'Background task',\n Bash: (input) => {\n const command = fieldString(input.command);\n\n return command ? `Running ${ command }` : 'Running command';\n },\n Fetch: input => `Fetching ${ fieldString(input.url) ?? 'page' }`,\n Skill: input => `Loading ${ fieldString(input.name) ?? 'skill' }`,\n GetMcpResources: (input) => {\n const uri = fieldString(input.uri);\n\n if (uri) {\n const tail = uri.replace(/\\/+$/, '').split('/').pop()?.trim();\n\n return `Reading ${ tail || uri }`;\n }\n\n return 'Listing MCP resources';\n },\n Preamble: input => fieldString(input.content),\n ReadLints: () => 'Checking lints',\n PageScreenshot: () => 'Capturing screenshot',\n CheckPage: () => 'Checking pages',\n DevServerStatus: () => 'Checking project',\n ImportAsset: () => 'Importing asset',\n CreatePlan: () => 'Creating plan',\n EditPlan: () => 'Editing plan',\n ReadPlan: () => 'Reading plan',\n};\n\n/** One composer strip: who is running, and the child thread Show opens. */\nexport function subagentComposerCopy(\n part: { input?: unknown; output?: unknown },\n patch: Record<string, unknown> | undefined\n): { text: string; label: string; childThreadId?: string; waiting: boolean } {\n const name = agentNameFromPart(part);\n const label = subagentLabel(name);\n const waiting = patch?.needsUser === true;\n const childThreadId = fieldString((part.output as AgentToolOutput | undefined)?.childThreadId)\n ?? fieldString(patch?.childThreadId);\n const text = waiting\n ? `${ label } · Waiting for you`\n : `${ label } Agent working`;\n\n return { text, label, childThreadId, waiting };\n}\n\n/** Live subtitle for a tool — same copy for Agent rows and the compact rail task. */\nexport function subagentActivityLabel(patch: Record<string, unknown> | undefined): string | undefined {\n if (!patch) {\n return undefined;\n }\n\n if (patch.type === 'text') {\n return 'Finishing reply';\n }\n\n if (patch.type === 'reasoning') {\n return 'Thinking…';\n }\n\n const toolName = fieldString(patch.toolName);\n\n if (!toolName) {\n return undefined;\n }\n\n const rawInput = patch.input;\n const input = (rawInput != null && typeof rawInput === 'object' && !Array.isArray(rawInput))\n ? rawInput as Record<string, unknown>\n : {};\n\n return TOOL_ACTIVITY[toolName]?.(input)\n ?? `Using ${ fieldString(patch.title) ?? humanizeString(toolName) }`;\n}\n\n/** Live/waiting subtitle. Done rows stay quiet — no empty \"Completed\". */\nexport function agentStatusLine(input: {\n live: boolean;\n failed: boolean;\n stalled?: boolean;\n needsUser?: boolean;\n activity?: string;\n}): string | undefined {\n if (input.failed || input.stalled) {\n return undefined;\n }\n\n if (input.needsUser) {\n return 'Waiting for you';\n }\n\n if (!input.live) {\n return undefined;\n }\n\n return input.activity ?? 'Starting…';\n}\n\n/** Subagent card. Running: loader, shimmer title, gray activity. Finished: same frame, quiet title. */\nfunction AgentCard({\n title,\n activity,\n errorText,\n running,\n stalled,\n onOpen,\n}: {\n title: string;\n activity?: string;\n errorText?: string;\n running: boolean;\n stalled: boolean;\n onOpen?: () => void;\n}) {\n const heading = stalled ? TOOL_INTERRUPTED_MESSAGE : title;\n const copy = (\n <Box align=\"center\" direction=\"row\" fullWidth gap=\"md\" padding=\"md\">\n <Show\n when={ running }\n fallback={ <Message aria-hidden /> }\n >\n <ProgressLoader aria-hidden size={ 14 } />\n </Show>\n <Box gap=\"xxs\" grow>\n <Show\n when={ running }\n fallback={ (\n <Text className={ styles.title } color={ stalled ? 'secondary' : undefined }>\n { heading }\n </Text>\n ) }\n >\n <Shimmer as=\"span\" className={ styles.title } duration={ 1 }>\n { heading }\n </Shimmer>\n </Show>\n <Show when={ running ? activity : undefined }>\n { line => (\n <Text color=\"secondary\" truncate variant=\"sm\">\n { line }\n </Text>\n ) }\n </Show>\n <Show when={ errorText }>\n { line => (\n <Text color=\"danger\" variant=\"xs\">{ line }</Text>\n ) }\n </Show>\n </Box>\n </Box>\n );\n\n return (\n <ToolShellCard\n aria-busy={ running || undefined }\n className={ shellStyles.tool }\n collapsible={ false }\n data-slot=\"agent-tool\"\n >\n <Show\n when={ onOpen }\n fallback={ copy }\n >\n { open => (\n <Pressable\n aria-label={ activity ? `${ heading }. ${ activity }` : heading }\n className={ styles.hit }\n onPress={ open }\n >\n { copy }\n </Pressable>\n ) }\n </Show>\n </ToolShellCard>\n );\n}\n\n/** Agent subagent card. Opens the child thread. */\nexport const AgentTool = observer(({ part }: ToolRendererProps) => {\n const turn = useMessageTurn();\n const { onOpenSubagent } = useChat();\n const patch = turn?.getToolMeta?.(part.toolCallId)?.patch;\n const needsUser = patch?.needsUser === true;\n const { live, stalled } = useToolProgress(part.state, needsUser);\n\n if (!isToolUIPart(part) || getToolName(part) !== 'Agent') {\n return null;\n }\n\n const failure = getToolFailureRowState(part);\n const logicalError = part.state === 'output-available'\n ? agentErrorFromOutput(part.output)\n : undefined;\n const failed = failure.useFailureLabel || Boolean(logicalError);\n const agentName = agentNameFromPart(part);\n const label = subagentLabel(agentName);\n const background = part.state === 'output-available' && Boolean((part.output as AgentToolOutput | undefined)?.jobId);\n const phase = agentPhaseCopy(agentName, background);\n const activity = subagentActivityLabel(patch);\n const statusLine = agentStatusLine({\n live,\n failed,\n stalled,\n needsUser,\n activity,\n });\n const childThreadId = fieldString((part.output as AgentToolOutput | undefined)?.childThreadId)\n ?? fieldString(patch?.childThreadId);\n const canOpen = Boolean(childThreadId && onOpenSubagent && !failed);\n const errorText = logicalError ?? failure.problemText ?? failure.tooltip;\n const openChild = canOpen\n ? () => onOpenSubagent?.(childThreadId!, label)\n : undefined;\n\n return (\n <AgentCard\n activity={ statusLine }\n errorText={ errorText }\n onOpen={ openChild }\n running={ live && !failed && !stalled }\n stalled={ stalled }\n title={ live && !failed && !stalled ? phase.live : phase.done }\n />\n );\n});\n"],"names":["SUBAGENT_LABELS","SUBAGENT_LIVE","agentErrorFromOutput","output","error","agentNameFromPart","part","source","name","subagentLabel","id","mapped","agentPhaseCopy","background","label","fieldString","value","trimmed","fileLabel","input","path","basename","files","item","plural","fileActivity","verb","fallback","TOOL_ACTIVITY","command","uri","subagentComposerCopy","patch","waiting","childThreadId","subagentActivityLabel","toolName","rawInput","humanizeString","agentStatusLine","AgentCard","title","activity","errorText","running","stalled","onOpen","heading","TOOL_INTERRUPTED_MESSAGE","copy","Box","_jsx","Show","Message","ProgressLoader","_jsxs","Text","styles","Shimmer","line","ToolShellCard","shellStyles","open","Pressable","AgentTool","observer","turn","useMessageTurn","onOpenSubagent","useChat","needsUser","live","useToolProgress","isToolUIPart","getToolName","failure","getToolFailureRowState","logicalError","failed","agentName","phase","statusLine","canOpen"],"mappings":"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"}
@@ -1,14 +1,14 @@
1
- import { Completed as b, Oclock as k, Terminal as y } from "@reforma/icons/14";
2
- import { isStaticToolUIPart as w, getToolName as C } from "@reforma/types";
1
+ import { Completed as x, Oclock as b, Terminal as k } from "@reforma/icons/14";
2
+ import { isStaticToolUIPart as y, getToolName as w } from "@reforma/types";
3
3
  import { useMemo as u } from "react";
4
4
  import { Show as h } from "../../../Show/Show.js";
5
- import { TerminalContent as S } from "../../../Terminal/Terminal.js";
6
- import { Text as O } from "../../../Text/Text.js";
7
- import { Approval as R, ApprovalRequest as j, ApprovalButtons as A } from "../../Approval/Approval.js";
8
- import { getToolFailureRowState as P, isToolInvocationInProgress as $ } from "../helpers.js";
9
- import { ToolShell as F, ToolShellHeader as I, ToolShellContent as N, ToolShellFooter as q } from "../shell/ToolShell.js";
10
- import g from "./BashTool.module.css.js";
11
- import { jsxs as T, jsx as s } from "react/jsx-runtime";
5
+ import { TerminalContent as C } from "../../../Terminal/Terminal.js";
6
+ import { Text as S } from "../../../Text/Text.js";
7
+ import { Approval as O, ApprovalRequest as R, ApprovalButtons as j } from "../../Approval/Approval.js";
8
+ import { getToolFailureRowState as A, isToolInvocationInProgress as P } from "../helpers.js";
9
+ import { ToolShell as $, ToolShellHeader as F, ToolShellContent as I, ToolShellFooter as N } from "../shell/ToolShell.js";
10
+ import q from "./BashTool.module.css.js";
11
+ import { jsxs as g, jsx as s } from "react/jsx-runtime";
12
12
  function D(t) {
13
13
  const r = t?.input;
14
14
  if (r == null || typeof r != "object")
@@ -59,7 +59,7 @@ function M(t, r) {
59
59
  function _(t, r) {
60
60
  return l(t) ? r.status === "running" ? "Background task" : "Background task finished" : t.description !== "" ? t.description : t.command !== "" ? t.command : "Bash";
61
61
  }
62
- function B(t) {
62
+ function T(t) {
63
63
  const r = [];
64
64
  return typeof t.exitCode == "number" && r.push(`exit ${t.exitCode}`), t.signal && r.push(`signal ${t.signal}`), r.length === 0 && t.status && t.status !== "running" && r.push(t.status), r.join(`
65
65
  `);
@@ -79,7 +79,7 @@ function U(t) {
79
79
  `), n += `\x1B[31m${o}\x1B[0m`), n;
80
80
  }
81
81
  function W(t, r) {
82
- const o = U(r), e = [t.command === "" ? B(r) : "", o].filter((i) => i !== "").join(`
82
+ const o = U(r), e = [t.command === "" ? T(r) : "", o].filter((i) => i !== "").join(`
83
83
  `);
84
84
  return t.command === "" ? e : `${z} ${E(t.command)}
85
85
  ` + e;
@@ -87,47 +87,46 @@ function W(t, r) {
87
87
  function rt(t) {
88
88
  const {
89
89
  onToolApprovalResponse: r
90
- } = t, o = w(t.part) && C(t.part) === "Bash" ? t.part : null, n = u(() => D(o), [o]), e = u(() => H(o), [o]), a = u(() => W(n, e), [n, e]);
90
+ } = t, o = y(t.part) && w(t.part) === "Bash" ? t.part : null, n = u(() => D(o), [o]), e = u(() => H(o), [o]), a = u(() => W(n, e), [n, e]);
91
91
  if (!o)
92
92
  return null;
93
- const i = o.state, c = P(o), d = o.approval, m = $(i, !0), v = !!(e.stdout || e.stderr || B(e)), f = n.command !== "" || v, p = M(n, e), x = L(n) && !p;
94
- return /* @__PURE__ */ T(F, {
93
+ const i = o.state, c = A(o), d = o.approval, m = P(i, !0), B = !!(e.stdout || e.stderr || T(e)), f = n.command !== "" || B, p = M(n, e), v = L(n) && !p;
94
+ return /* @__PURE__ */ g($, {
95
95
  collapsible: f,
96
96
  "data-slot": "bash-tool",
97
- children: [/* @__PURE__ */ s(I, {
97
+ children: [/* @__PURE__ */ s(F, {
98
98
  state: i,
99
99
  statusDetail: c.tooltip,
100
100
  title: _(n, e),
101
101
  truncateTitle: !0,
102
- icon: p ? /* @__PURE__ */ s(b, {
102
+ icon: p ? /* @__PURE__ */ s(x, {
103
103
  "aria-hidden": !0
104
- }) : x ? /* @__PURE__ */ s(k, {
104
+ }) : v ? /* @__PURE__ */ s(b, {
105
105
  "aria-hidden": !0
106
- }) : /* @__PURE__ */ s(y, {
106
+ }) : /* @__PURE__ */ s(k, {
107
107
  "aria-hidden": !0
108
108
  })
109
109
  }), /* @__PURE__ */ s(h, {
110
110
  when: f,
111
- children: /* @__PURE__ */ s(N, {
112
- className: g.content,
113
- children: /* @__PURE__ */ s(S, {
111
+ children: /* @__PURE__ */ s(I, {
112
+ children: /* @__PURE__ */ s(C, {
114
113
  autoScroll: m,
115
114
  isStreaming: m,
116
115
  output: a,
117
- className: g.terminalPanel
116
+ className: q.terminalPanel
118
117
  })
119
118
  })
120
119
  }), /* @__PURE__ */ s(h, {
121
120
  when: i === "approval-requested",
122
- children: /* @__PURE__ */ s(q, {
123
- children: /* @__PURE__ */ s(R, {
121
+ children: /* @__PURE__ */ s(N, {
122
+ children: /* @__PURE__ */ s(O, {
124
123
  approval: d,
125
124
  state: i,
126
125
  onToolApprovalResponse: r,
127
- children: /* @__PURE__ */ T(j, {
128
- children: [/* @__PURE__ */ s(O, {
126
+ children: /* @__PURE__ */ g(R, {
127
+ children: [/* @__PURE__ */ s(S, {
129
128
  children: "Confirm you want to run this command"
130
- }), /* @__PURE__ */ s(A, {})]
129
+ }), /* @__PURE__ */ s(j, {})]
131
130
  })
132
131
  })
133
132
  })
@@ -1 +1 @@
1
- {"version":3,"file":"BashTool.js","sources":["../../../../src/chat/Tool/bash/BashTool.tsx"],"sourcesContent":["import { Completed, Oclock, Terminal } from '@reforma/icons/14';\nimport { getToolName, isStaticToolUIPart } from '@reforma/types';\nimport { useMemo } from 'react';\n\nimport { Show } from '../../../Show';\nimport { TerminalContent } from '../../../Terminal';\nimport { Text } from '../../../Text';\nimport {\n Approval,\n ApprovalButtons,\n ApprovalRequest,\n} from '../../Approval';\nimport {\n getToolFailureRowState,\n isToolInvocationInProgress,\n} from '../helpers';\nimport {\n ToolShell,\n ToolShellContent,\n ToolShellFooter,\n ToolShellHeader,\n} from '../shell';\nimport styles from './BashTool.module.css';\n\nimport type { ToolUIPart } from 'ai';\nimport type { ToolRendererProps } from '../types';\n\ntype ParsedBashInput = {\n command: string;\n description: string;\n cwd?: string;\n id?: string;\n background: boolean;\n};\n\nfunction parseBashInput(part: ToolUIPart | null): ParsedBashInput {\n const input = part?.input;\n\n if (input == null || typeof input !== 'object') {\n return {\n command: '',\n description: '',\n background: false,\n };\n }\n\n const o = input as Record<string, unknown>;\n const command = typeof o.command === 'string' ? o.command : '';\n const description = typeof o.description === 'string' ? o.description.trim() : '';\n const cwd = typeof o.cwd === 'string' ? o.cwd.trim() : undefined;\n const id = typeof o.id === 'string' ? o.id.trim() : '';\n\n return {\n command,\n description,\n cwd: cwd !== '' ? cwd : undefined,\n id: id !== '' ? id : undefined,\n background: o.background === true,\n };\n}\n\ntype ParsedBashOutput = {\n stdout?: string;\n stderr?: string;\n status?: string;\n exitCode?: number;\n signal?: string;\n};\n\nfunction parseBashOutput(part: ToolUIPart | null): ParsedBashOutput {\n if (!part) {\n return {\n stdout: '',\n stderr: '',\n };\n }\n\n const isError = part.state === 'output-error';\n const output = (part.output ?? '') as ParsedBashOutput | string;\n\n if (typeof output === 'string') {\n return {\n stdout: output,\n stderr: isError ? part.errorText : '',\n };\n }\n\n const record = output as Record<string, unknown>;\n const stdout = typeof record.stdout === 'string' ? record.stdout : undefined;\n const stderr = typeof record.stderr === 'string' ? record.stderr : undefined;\n const status = typeof record.status === 'string' ? record.status : undefined;\n const signal = typeof record.signal === 'string' ? record.signal : undefined;\n const exitCode = typeof record.exitCode === 'number' ? record.exitCode : undefined;\n\n return {\n stdout,\n stderr,\n status,\n exitCode,\n signal,\n };\n}\n\n/** A poll or finished job: id, no command. The launch itself still has a command. */\nfunction isBackgroundResult(input: ParsedBashInput): boolean {\n return input.command === '' && (input.background || input.id != null);\n}\n\nfunction isBackgroundBash(input: ParsedBashInput): boolean {\n return input.background || isBackgroundResult(input);\n}\n\n/** Poll that already left the running state. Still-running work keeps the clock and badge. */\nfunction isFinishedBackgroundResult(input: ParsedBashInput, output: ParsedBashOutput): boolean {\n return isBackgroundResult(input) && output.status !== 'running';\n}\n\nfunction bashTitle(input: ParsedBashInput, output: ParsedBashOutput): string {\n if (isBackgroundResult(input)) {\n return output.status === 'running' ? 'Background task' : 'Background task finished';\n }\n\n if (input.description !== '') {\n return input.description;\n }\n\n if (input.command !== '') {\n return input.command;\n }\n\n return 'Bash';\n}\n\nfunction backgroundResultNote(output: ParsedBashOutput): string {\n const lines: string[] = [];\n\n if (typeof output.exitCode === 'number') {\n lines.push(`exit ${ output.exitCode }`);\n }\n\n if (output.signal) {\n lines.push(`signal ${ output.signal }`);\n }\n\n if (lines.length === 0 && output.status && output.status !== 'running') {\n lines.push(output.status);\n }\n\n return lines.join('\\n');\n}\n\n/** Green `$` */\nconst BASH_PROMPT_DOLLAR = '\\x1b[32m$\\x1b[0m';\n\n/** Avoid breaking the ANSI stream if the command string ever contained escape bytes. */\nfunction sanitizeCommandForTerminalPrompt(command: string): string {\n return command.split('\\u001b').join('');\n}\n\n/** stdout + stderr (stderr wrapped in ANSI red). */\nfunction bashOutputForTerminal(parsed: ParsedBashOutput): string {\n const { stdout = '', stderr = '' } = parsed;\n let s = stdout;\n\n if (stderr) {\n if (s !== '' && !s.endsWith('\\n')) {\n s += '\\n';\n }\n\n s += `\\x1b[31m${ stderr }\\x1b[0m`;\n }\n\n return s;\n}\n\n/** `$ command` when there is one, then stdout/stderr. A result poll has no command. */\nfunction printToTerminal(input: ParsedBashInput, output: ParsedBashOutput): string {\n const body = bashOutputForTerminal(output);\n const note = input.command === '' ? backgroundResultNote(output) : '';\n const outputText = [note, body].filter(part => part !== '').join('\\n');\n\n if (input.command === '') {\n return outputText;\n }\n\n const line = `${ BASH_PROMPT_DOLLAR } ${ sanitizeCommandForTerminalPrompt(input.command) }\\n`;\n\n return line + outputText;\n}\n\nexport function BashTool(props: ToolRendererProps) {\n const { onToolApprovalResponse } = props;\n\n const part = (isStaticToolUIPart(props.part) && getToolName(props.part) === 'Bash')\n ? props.part\n : null;\n\n const parsedInput = useMemo(() => parseBashInput(part), [part]);\n const parsedOutput = useMemo(() => parseBashOutput(part), [part]);\n\n const printOutput = useMemo(\n () => printToTerminal(parsedInput, parsedOutput),\n [parsedInput, parsedOutput]\n );\n\n if (!part) {\n return null;\n }\n\n const state = part.state;\n const failure = getToolFailureRowState(part);\n const approval = part.approval;\n const live = isToolInvocationInProgress(state, true);\n\n const hasOutput = Boolean(parsedOutput.stdout || parsedOutput.stderr || backgroundResultNote(parsedOutput));\n const showTerminal = parsedInput.command !== '' || hasOutput;\n const finished = isFinishedBackgroundResult(parsedInput, parsedOutput);\n const background = isBackgroundBash(parsedInput) && !finished;\n\n return (\n <ToolShell\n collapsible={ showTerminal }\n data-slot=\"bash-tool\"\n >\n <ToolShellHeader\n state={ state }\n statusDetail={ failure.tooltip }\n title={ bashTitle(parsedInput, parsedOutput) }\n truncateTitle\n icon={ finished\n ? <Completed aria-hidden />\n : background\n ? <Oclock aria-hidden />\n : <Terminal aria-hidden /> }\n />\n\n <Show when={ showTerminal }>\n <ToolShellContent className={ styles.content }>\n <TerminalContent\n autoScroll={ live }\n isStreaming={ live }\n output={ printOutput }\n className={ styles.terminalPanel }\n />\n </ToolShellContent>\n </Show>\n\n <Show when={ state === 'approval-requested' }>\n <ToolShellFooter>\n <Approval\n approval={ approval }\n state={ state }\n onToolApprovalResponse={ onToolApprovalResponse }\n >\n <ApprovalRequest>\n <Text>Confirm you want to run this command</Text>\n <ApprovalButtons />\n </ApprovalRequest>\n </Approval>\n </ToolShellFooter>\n </Show>\n </ToolShell>\n );\n}\n"],"names":["parseBashInput","part","input","command","description","cwd","id","parseBashOutput","isError","output","record","stdout","stderr","status","signal","exitCode","isBackgroundResult","isBackgroundBash","isFinishedBackgroundResult","bashTitle","backgroundResultNote","lines","BASH_PROMPT_DOLLAR","sanitizeCommandForTerminalPrompt","bashOutputForTerminal","parsed","s","printToTerminal","body","outputText","BashTool","props","onToolApprovalResponse","isStaticToolUIPart","getToolName","parsedInput","useMemo","parsedOutput","printOutput","state","failure","getToolFailureRowState","approval","live","isToolInvocationInProgress","hasOutput","showTerminal","finished","background","ToolShell","_jsx","ToolShellHeader","Completed","Oclock","Terminal","Show","ToolShellContent","styles","TerminalContent","ToolShellFooter","Approval","ApprovalRequest","Text","ApprovalButtons"],"mappings":"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"}
1
+ {"version":3,"file":"BashTool.js","sources":["../../../../src/chat/Tool/bash/BashTool.tsx"],"sourcesContent":["import { Completed, Oclock, Terminal } from '@reforma/icons/14';\nimport { getToolName, isStaticToolUIPart } from '@reforma/types';\nimport { useMemo } from 'react';\n\nimport { Show } from '../../../Show';\nimport { TerminalContent } from '../../../Terminal';\nimport { Text } from '../../../Text';\nimport {\n Approval,\n ApprovalButtons,\n ApprovalRequest,\n} from '../../Approval';\nimport {\n getToolFailureRowState,\n isToolInvocationInProgress,\n} from '../helpers';\nimport {\n ToolShell,\n ToolShellContent,\n ToolShellFooter,\n ToolShellHeader,\n} from '../shell';\nimport styles from './BashTool.module.css';\n\nimport type { ToolUIPart } from 'ai';\nimport type { ToolRendererProps } from '../types';\n\ntype ParsedBashInput = {\n command: string;\n description: string;\n cwd?: string;\n id?: string;\n background: boolean;\n};\n\nfunction parseBashInput(part: ToolUIPart | null): ParsedBashInput {\n const input = part?.input;\n\n if (input == null || typeof input !== 'object') {\n return {\n command: '',\n description: '',\n background: false,\n };\n }\n\n const o = input as Record<string, unknown>;\n const command = typeof o.command === 'string' ? o.command : '';\n const description = typeof o.description === 'string' ? o.description.trim() : '';\n const cwd = typeof o.cwd === 'string' ? o.cwd.trim() : undefined;\n const id = typeof o.id === 'string' ? o.id.trim() : '';\n\n return {\n command,\n description,\n cwd: cwd !== '' ? cwd : undefined,\n id: id !== '' ? id : undefined,\n background: o.background === true,\n };\n}\n\ntype ParsedBashOutput = {\n stdout?: string;\n stderr?: string;\n status?: string;\n exitCode?: number;\n signal?: string;\n};\n\nfunction parseBashOutput(part: ToolUIPart | null): ParsedBashOutput {\n if (!part) {\n return {\n stdout: '',\n stderr: '',\n };\n }\n\n const isError = part.state === 'output-error';\n const output = (part.output ?? '') as ParsedBashOutput | string;\n\n if (typeof output === 'string') {\n return {\n stdout: output,\n stderr: isError ? part.errorText : '',\n };\n }\n\n const record = output as Record<string, unknown>;\n const stdout = typeof record.stdout === 'string' ? record.stdout : undefined;\n const stderr = typeof record.stderr === 'string' ? record.stderr : undefined;\n const status = typeof record.status === 'string' ? record.status : undefined;\n const signal = typeof record.signal === 'string' ? record.signal : undefined;\n const exitCode = typeof record.exitCode === 'number' ? record.exitCode : undefined;\n\n return {\n stdout,\n stderr,\n status,\n exitCode,\n signal,\n };\n}\n\n/** A poll or finished job: id, no command. The launch itself still has a command. */\nfunction isBackgroundResult(input: ParsedBashInput): boolean {\n return input.command === '' && (input.background || input.id != null);\n}\n\nfunction isBackgroundBash(input: ParsedBashInput): boolean {\n return input.background || isBackgroundResult(input);\n}\n\n/** Poll that already left the running state. Still-running work keeps the clock and badge. */\nfunction isFinishedBackgroundResult(input: ParsedBashInput, output: ParsedBashOutput): boolean {\n return isBackgroundResult(input) && output.status !== 'running';\n}\n\nfunction bashTitle(input: ParsedBashInput, output: ParsedBashOutput): string {\n if (isBackgroundResult(input)) {\n return output.status === 'running' ? 'Background task' : 'Background task finished';\n }\n\n if (input.description !== '') {\n return input.description;\n }\n\n if (input.command !== '') {\n return input.command;\n }\n\n return 'Bash';\n}\n\nfunction backgroundResultNote(output: ParsedBashOutput): string {\n const lines: string[] = [];\n\n if (typeof output.exitCode === 'number') {\n lines.push(`exit ${ output.exitCode }`);\n }\n\n if (output.signal) {\n lines.push(`signal ${ output.signal }`);\n }\n\n if (lines.length === 0 && output.status && output.status !== 'running') {\n lines.push(output.status);\n }\n\n return lines.join('\\n');\n}\n\n/** Green `$` */\nconst BASH_PROMPT_DOLLAR = '\\x1b[32m$\\x1b[0m';\n\n/** Avoid breaking the ANSI stream if the command string ever contained escape bytes. */\nfunction sanitizeCommandForTerminalPrompt(command: string): string {\n return command.split('\\u001b').join('');\n}\n\n/** stdout + stderr (stderr wrapped in ANSI red). */\nfunction bashOutputForTerminal(parsed: ParsedBashOutput): string {\n const { stdout = '', stderr = '' } = parsed;\n let s = stdout;\n\n if (stderr) {\n if (s !== '' && !s.endsWith('\\n')) {\n s += '\\n';\n }\n\n s += `\\x1b[31m${ stderr }\\x1b[0m`;\n }\n\n return s;\n}\n\n/** `$ command` when there is one, then stdout/stderr. A result poll has no command. */\nfunction printToTerminal(input: ParsedBashInput, output: ParsedBashOutput): string {\n const body = bashOutputForTerminal(output);\n const note = input.command === '' ? backgroundResultNote(output) : '';\n const outputText = [note, body].filter(part => part !== '').join('\\n');\n\n if (input.command === '') {\n return outputText;\n }\n\n const line = `${ BASH_PROMPT_DOLLAR } ${ sanitizeCommandForTerminalPrompt(input.command) }\\n`;\n\n return line + outputText;\n}\n\nexport function BashTool(props: ToolRendererProps) {\n const { onToolApprovalResponse } = props;\n\n const part = (isStaticToolUIPart(props.part) && getToolName(props.part) === 'Bash')\n ? props.part\n : null;\n\n const parsedInput = useMemo(() => parseBashInput(part), [part]);\n const parsedOutput = useMemo(() => parseBashOutput(part), [part]);\n\n const printOutput = useMemo(\n () => printToTerminal(parsedInput, parsedOutput),\n [parsedInput, parsedOutput]\n );\n\n if (!part) {\n return null;\n }\n\n const state = part.state;\n const failure = getToolFailureRowState(part);\n const approval = part.approval;\n const live = isToolInvocationInProgress(state, true);\n\n const hasOutput = Boolean(parsedOutput.stdout || parsedOutput.stderr || backgroundResultNote(parsedOutput));\n const showTerminal = parsedInput.command !== '' || hasOutput;\n const finished = isFinishedBackgroundResult(parsedInput, parsedOutput);\n const background = isBackgroundBash(parsedInput) && !finished;\n\n return (\n <ToolShell\n collapsible={ showTerminal }\n data-slot=\"bash-tool\"\n >\n <ToolShellHeader\n state={ state }\n statusDetail={ failure.tooltip }\n title={ bashTitle(parsedInput, parsedOutput) }\n truncateTitle\n icon={ finished\n ? <Completed aria-hidden />\n : background\n ? <Oclock aria-hidden />\n : <Terminal aria-hidden /> }\n />\n\n <Show when={ showTerminal }>\n <ToolShellContent>\n <TerminalContent\n autoScroll={ live }\n isStreaming={ live }\n output={ printOutput }\n className={ styles.terminalPanel }\n />\n </ToolShellContent>\n </Show>\n\n <Show when={ state === 'approval-requested' }>\n <ToolShellFooter>\n <Approval\n approval={ approval }\n state={ state }\n onToolApprovalResponse={ onToolApprovalResponse }\n >\n <ApprovalRequest>\n <Text>Confirm you want to run this command</Text>\n <ApprovalButtons />\n </ApprovalRequest>\n </Approval>\n </ToolShellFooter>\n </Show>\n </ToolShell>\n );\n}\n"],"names":["parseBashInput","part","input","command","description","cwd","id","parseBashOutput","isError","output","record","stdout","stderr","status","signal","exitCode","isBackgroundResult","isBackgroundBash","isFinishedBackgroundResult","bashTitle","backgroundResultNote","lines","BASH_PROMPT_DOLLAR","sanitizeCommandForTerminalPrompt","bashOutputForTerminal","parsed","s","printToTerminal","body","outputText","BashTool","props","onToolApprovalResponse","isStaticToolUIPart","getToolName","parsedInput","useMemo","parsedOutput","printOutput","state","failure","getToolFailureRowState","approval","live","isToolInvocationInProgress","hasOutput","showTerminal","finished","background","ToolShell","_jsx","ToolShellHeader","Completed","Oclock","Terminal","Show","ToolShellContent","TerminalContent","styles","ToolShellFooter","Approval","ApprovalRequest","Text","ApprovalButtons"],"mappings":"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"}
@@ -1 +1 @@
1
- .BashTool_content_jQUS2j{padding:0}.BashTool_terminalPanel_bCKi82{--terminal-max-body-height: none}
1
+ .BashTool_terminalPanel_bCKi82{--terminal-max-body-height: none;border-radius:calc(var(--radius-lg) * var(--squircle-radius-factor));corner-shape:superellipse(var(--squircle-value));border:1px solid var(--color-secondary-muted);background-color:var(--color-background);color:var(--color-text)}
@@ -1,10 +1,8 @@
1
- const n = "BashTool_content_jQUS2j", t = "BashTool_terminalPanel_bCKi82", e = {
2
- content: n,
3
- terminalPanel: t
1
+ const a = "BashTool_terminalPanel_bCKi82", e = {
2
+ terminalPanel: a
4
3
  };
5
4
  export {
6
- n as content,
7
5
  e as default,
8
- t as terminalPanel
6
+ a as terminalPanel
9
7
  };
10
8
  //# sourceMappingURL=BashTool.module.css.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BashTool.module.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
1
+ {"version":3,"file":"BashTool.module.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
@@ -183,7 +183,7 @@ function oe({
183
183
  }) {
184
184
  return s ? /* @__PURE__ */ t(f, {
185
185
  className: i.title,
186
- color: "danger",
186
+ color: "secondary",
187
187
  children: H
188
188
  }) : n ? /* @__PURE__ */ t(j, {
189
189
  as: "span",
@@ -1 +1 @@
1
- {"version":3,"file":"ImageAssetTool.js","sources":["../../../../src/chat/Tool/image-asset/ImageAssetTool.tsx"],"sourcesContent":["import { AttentionTriangle } from '@reforma/icons/14';\nimport { ProgressLoader } from '@reforma/icons/assets';\nimport { getToolName } from '@reforma/types';\n\nimport { Box } from '../../../Box';\nimport { For } from '../../../For';\nimport { Image } from '../../../Image';\nimport { Lightbox, type LightboxOpen } from '../../../Lightbox';\nimport { Pressable } from '../../../Pressable';\nimport { Shimmer } from '../../../Shimmer';\nimport { Show } from '../../../Show';\nimport { Text } from '../../../Text';\nimport { useChat } from '../../ChatContext';\nimport { getToolFailureRowState, isToolInvocationInProgress, TOOL_INTERRUPTED_MESSAGE } from '../helpers';\nimport {\n ToolShellCard,\n} from '../shell';\nimport { useToolProgress } from '../shell/toolProgress';\nimport shellStyles from '../shell/ToolShellCard.module.css';\nimport { FailedToolTitleTooltip } from '../shell/ToolShellStatusIcon';\nimport styles from './ImageAssetTool.module.css';\n\nimport type { CSSProperties } from 'react';\nimport type { ToolRendererProps } from '../types';\n\ntype ImageCredit = {\n name: string;\n profileUrl: string;\n unsplashUrl: string;\n};\n\ntype ImageAsset = {\n url?: string;\n path?: string;\n publicPath?: string;\n previewUrl?: string;\n mediaType?: string;\n alt?: string;\n credit?: ImageCredit;\n};\n\ntype ImageAssetSuccess = {\n ok: true;\n alt?: string;\n query?: string;\n images: ImageAsset[];\n};\n\ntype ImageAssetFailure = {\n ok: false;\n error: string;\n alt?: string;\n query?: string;\n};\n\nconst IMAGE_TOOL_NAMES = new Set(['ImageGen', 'SearchImage', 'ImportAsset']);\n\nfunction parseOutput(output: unknown): ImageAssetSuccess | ImageAssetFailure | undefined {\n if (typeof output !== 'object' || output === null || !('ok' in output)) {\n return undefined;\n }\n\n return output as ImageAssetSuccess | ImageAssetFailure;\n}\n\n/** Absolute asset URL, or chat `previewUrl` + site `publicPath` (filesystem saves). */\nfunction previewSrc(image: ImageAsset, host?: string): string | undefined {\n const absolute = image.url?.trim() || image.previewUrl?.trim();\n\n if (absolute) {\n return absolute;\n }\n\n const publicPath = image.publicPath?.trim();\n\n if (!publicPath || !host) {\n return undefined;\n }\n\n try {\n return new URL(publicPath, host).href;\n }\n catch {\n return undefined;\n }\n}\n\nfunction titlesFor(toolName: string, count: number): { idle: string; progress: string } {\n if (toolName === 'SearchImage') {\n if (count > 1) {\n return { progress: `Finding ${ count } photos`, idle: `Found ${ count } photos` };\n }\n\n return { progress: 'Finding photos', idle: 'Found photos' };\n }\n\n if (toolName === 'ImportAsset') {\n return { progress: 'Importing file', idle: 'Imported file' };\n }\n\n if (count > 1) {\n return { progress: `Generating ${ count } images`, idle: `Generated ${ count } images` };\n }\n\n return { progress: 'Generating image', idle: 'Generated image' };\n}\n\nfunction failureTitle(toolName: string): string {\n if (toolName === 'SearchImage') {\n return 'Couldn\\'t find photos';\n }\n\n if (toolName === 'ImportAsset') {\n return 'Couldn\\'t import file';\n }\n\n return 'Couldn\\'t generate the image';\n}\n\nfunction CreditCaption({ credit }: { credit: ImageCredit }) {\n const profileHref = credit.profileUrl.trim();\n const unsplashHref = credit.unsplashUrl.trim() || 'https://unsplash.com';\n\n return (\n <Text variant=\"xs\" className={ styles.credit }>\n Photo by\n { ' ' }\n <Show\n when={ profileHref }\n fallback={ <span>{ credit.name }</span> }\n >\n {href => (\n <a\n className={ styles.creditLink }\n href={ href }\n rel=\"noreferrer\"\n target=\"_blank\"\n >\n { credit.name }\n </a>\n )}\n </Show>\n { ' / ' }\n <a\n className={ styles.creditLink }\n href={ unsplashHref }\n rel=\"noreferrer\"\n target=\"_blank\"\n >\n Unsplash\n </a>\n </Text>\n );\n}\n\ntype ToolInput = {\n alt?: string;\n query?: string;\n count?: unknown;\n prompts?: Array<{ alt?: string }>;\n};\n\nexport type ImageAssetFanSlot = {\n key: string;\n src?: string;\n alt: string;\n};\n\nfunction uniqueLines(values: Array<string | undefined>): string[] {\n const seen = new Set<string>();\n const lines: string[] = [];\n\n for (const value of values) {\n const line = value?.trim();\n\n if (!line || seen.has(line)) {\n continue;\n }\n\n seen.add(line);\n lines.push(line);\n }\n\n return lines;\n}\n\n/** Per-image alts, one each. Falls back to a joined ` · ` string by splitting it. */\nfunction captionLines(args: {\n images: ImageAsset[];\n prompts?: Array<{ alt?: string }>;\n fallback: string;\n}): string[] {\n const fromImages = uniqueLines(args.images.map(image => image.alt));\n\n if (fromImages.length > 0) {\n return fromImages;\n }\n\n const fromPrompts = uniqueLines((args.prompts ?? []).map(item => item.alt));\n\n if (fromPrompts.length > 0) {\n return fromPrompts;\n }\n\n if (args.fallback.includes(' · ')) {\n return uniqueLines(args.fallback.split(' · '));\n }\n\n return args.fallback ? [args.fallback] : [];\n}\n\nfunction requestedCount(input: ToolInput | undefined): number {\n const prompts = input?.prompts?.length ?? 0;\n const count = typeof input?.count === 'number' && input.count > 0 ? input.count : 0;\n\n return Math.max(prompts, count, 1);\n}\n\nfunction uniqueCredits(images: readonly ImageAsset[]): ImageCredit[] {\n const seen = new Set<string>();\n const credits: ImageCredit[] = [];\n\n for (const image of images) {\n if (!image.credit) {\n continue;\n }\n\n const key = image.credit.profileUrl || image.credit.name;\n\n if (seen.has(key)) {\n continue;\n }\n\n seen.add(key);\n credits.push(image.credit);\n }\n\n return credits;\n}\n\nfunction FanFace({ slot }: { slot: ImageAssetFanSlot }) {\n if (!slot.src) {\n return null;\n }\n\n const src = slot.src;\n\n return (\n <Lightbox alt={ slot.alt } src={ src }>\n {(open: LightboxOpen) => (\n <Pressable\n aria-label={ `View ${ slot.alt }` }\n className={ styles.fanHit }\n onPress={ open }\n >\n <Image alt=\"\" className={ styles.fanImage } src={ src } />\n </Pressable>\n )}\n </Lightbox>\n );\n}\n\nexport function ImageAssetThumbFan({\n badge,\n slots,\n}: {\n badge?: 'loader' | 'error';\n slots: readonly ImageAssetFanSlot[];\n}) {\n return (\n <div\n className={ styles.fan }\n data-count={ slots.length }\n style={ { '--n': slots.length } as CSSProperties }\n >\n <For each={ slots }>\n {(slot, index, { isLast }) => (\n <div\n key={ slot.key }\n className={ styles.fanCard }\n style={ { '--i': index } as CSSProperties }\n >\n <FanFace slot={ slot } />\n <Show when={ isLast && badge === 'loader' }>\n <ProgressLoader aria-hidden className={ styles.loader } size={ 14 } />\n </Show>\n <Show when={ isLast && badge === 'error' }>\n <AttentionTriangle aria-hidden className={ styles.errorMark } size={ 16 } />\n </Show>\n </div>\n )}\n </For>\n </div>\n );\n}\n\nexport function ImageAssetCardTitle({\n failed,\n idle,\n live,\n progress,\n stalled,\n statusDetail,\n}: {\n failed: boolean;\n idle: string;\n live: boolean;\n progress: string;\n stalled: boolean;\n statusDetail?: string;\n}) {\n if (stalled) {\n return (\n <Text className={ styles.title } color=\"danger\">\n { TOOL_INTERRUPTED_MESSAGE }\n </Text>\n );\n }\n\n if (live) {\n return (\n <Shimmer as=\"span\" className={ styles.title } duration={ 1 }>\n { progress }\n </Shimmer>\n );\n }\n\n if (failed) {\n return (\n <FailedToolTitleTooltip statusDetail={ statusDetail }>\n <Text className={ styles.title } color=\"secondary\" decoration=\"line-through\">\n { idle }\n </Text>\n </FailedToolTitleTooltip>\n );\n }\n\n return <Text className={ styles.title }>{ idle }</Text>;\n}\n\n/** Card for ImageGen / SearchImage — thumb row, or a plain shell row when nothing came back. */\nexport function ImageAssetTool({ part }: ToolRendererProps) {\n const toolName = getToolName(part);\n const { previewUrl } = useChat();\n const { live, stalled } = useToolProgress(part.state);\n\n if (!IMAGE_TOOL_NAMES.has(toolName)) {\n return null;\n }\n\n const state = part.state;\n const failure = getToolFailureRowState(part);\n const done = state === 'output-available';\n const output = done ? parseOutput(part.output) : undefined;\n const success = (output?.ok === true) ? output : undefined;\n const error = (output?.ok === false) ? output.error : failure.tooltip;\n const images = success?.images ?? [];\n const input = (typeof part.input === 'object' && part.input !== null)\n ? part.input as ToolInput\n : undefined;\n\n const outputAlt = (output && 'alt' in output && typeof output.alt === 'string')\n ? output.alt\n : undefined;\n const outputQuery = (output && 'query' in output && typeof output.query === 'string')\n ? output.query\n : undefined;\n // Prefer short alt (ImageGen); stock search falls back to search query — never the gen prompt.\n const fallback = (\n success?.alt\n || outputAlt\n || input?.alt\n || success?.query\n || outputQuery\n || input?.query\n || ''\n ).trim();\n\n const inProgress = isToolInvocationInProgress(state);\n const failedEmpty = !inProgress && images.length === 0;\n const total = images.length > 0 ? images.length : requestedCount(input);\n const titles = titlesFor(toolName, total);\n const lines = uniqueLines([\n ...captionLines({\n images,\n prompts: input?.prompts,\n fallback,\n }),\n ...images.flatMap(image => (previewSrc(image, previewUrl) ? [] : [image.path])),\n ]);\n const credits = uniqueCredits(images);\n const slots: ImageAssetFanSlot[] = failedEmpty\n ? [{ key: 'failed', alt: failureTitle(toolName) }]\n : images.length > 0\n ? images.map((image, index) => {\n const src = previewSrc(image, previewUrl);\n\n return {\n key: src || image.path || `image-${ index }`,\n src,\n alt: image.alt?.trim() || lines[index] || `Image ${ index + 1 }`,\n };\n })\n : Array.from({ length: total }, (_, index) => ({\n key: `placeholder-${ index }`,\n alt: lines[index] || titles.progress,\n }));\n\n return (\n <ToolShellCard\n aria-busy={ live }\n className={ shellStyles.tool }\n collapsible={ false }\n data-slot=\"image-asset-tool\"\n >\n <Box direction=\"row\" fullWidth gap=\"md\" padding=\"md\">\n <ImageAssetThumbFan\n badge={ live ? 'loader' : failedEmpty ? 'error' : undefined }\n slots={ slots }\n />\n <Box gap=\"xxs\" grow>\n <ImageAssetCardTitle\n failed={ !failedEmpty && Boolean(error) }\n idle={ failedEmpty ? failureTitle(toolName) : titles.idle }\n live={ live }\n progress={ titles.progress }\n stalled={ stalled }\n statusDetail={ error }\n />\n <Show when={ lines.length === 1 }>\n <Text className={ styles.caption } color=\"secondary\" variant=\"sm\">\n { lines[0] }\n </Text>\n </Show>\n <Show when={ lines.length > 1 }>\n <ul className={ styles.captions }>\n <For each={ lines }>\n {line => (\n <li key={ line }>\n <Text className={ styles.caption } color=\"secondary\" variant=\"sm\">\n { line }\n </Text>\n </li>\n )}\n </For>\n </ul>\n </Show>\n <Show when={ credits.length > 0 }>\n <div className={ styles.credits }>\n <For each={ credits }>\n {credit => (\n <CreditCaption\n key={ credit.profileUrl || credit.name }\n credit={ credit }\n />\n )}\n </For>\n </div>\n </Show>\n </Box>\n </Box>\n </ToolShellCard>\n );\n}\n"],"names":["IMAGE_TOOL_NAMES","parseOutput","output","previewSrc","image","host","absolute","publicPath","titlesFor","toolName","count","failureTitle","CreditCaption","credit","profileHref","unsplashHref","Text","styles","Show","href","_jsx","uniqueLines","values","seen","lines","value","line","captionLines","args","fromImages","fromPrompts","item","requestedCount","input","prompts","uniqueCredits","images","credits","key","FanFace","slot","src","Lightbox","open","Pressable","Image","ImageAssetThumbFan","badge","slots","For","index","isLast","ProgressLoader","AttentionTriangle","ImageAssetCardTitle","failed","idle","live","progress","stalled","statusDetail","TOOL_INTERRUPTED_MESSAGE","Shimmer","FailedToolTitleTooltip","ImageAssetTool","part","getToolName","previewUrl","useChat","useToolProgress","state","failure","getToolFailureRowState","success","error","outputAlt","outputQuery","fallback","failedEmpty","isToolInvocationInProgress","total","titles","_","ToolShellCard","shellStyles","Box","_jsxs"],"mappings":"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"}
1
+ {"version":3,"file":"ImageAssetTool.js","sources":["../../../../src/chat/Tool/image-asset/ImageAssetTool.tsx"],"sourcesContent":["import { AttentionTriangle } from '@reforma/icons/14';\nimport { ProgressLoader } from '@reforma/icons/assets';\nimport { getToolName } from '@reforma/types';\n\nimport { Box } from '../../../Box';\nimport { For } from '../../../For';\nimport { Image } from '../../../Image';\nimport { Lightbox, type LightboxOpen } from '../../../Lightbox';\nimport { Pressable } from '../../../Pressable';\nimport { Shimmer } from '../../../Shimmer';\nimport { Show } from '../../../Show';\nimport { Text } from '../../../Text';\nimport { useChat } from '../../ChatContext';\nimport { getToolFailureRowState, isToolInvocationInProgress, TOOL_INTERRUPTED_MESSAGE } from '../helpers';\nimport {\n ToolShellCard,\n} from '../shell';\nimport { useToolProgress } from '../shell/toolProgress';\nimport shellStyles from '../shell/ToolShellCard.module.css';\nimport { FailedToolTitleTooltip } from '../shell/ToolShellStatusIcon';\nimport styles from './ImageAssetTool.module.css';\n\nimport type { CSSProperties } from 'react';\nimport type { ToolRendererProps } from '../types';\n\ntype ImageCredit = {\n name: string;\n profileUrl: string;\n unsplashUrl: string;\n};\n\ntype ImageAsset = {\n url?: string;\n path?: string;\n publicPath?: string;\n previewUrl?: string;\n mediaType?: string;\n alt?: string;\n credit?: ImageCredit;\n};\n\ntype ImageAssetSuccess = {\n ok: true;\n alt?: string;\n query?: string;\n images: ImageAsset[];\n};\n\ntype ImageAssetFailure = {\n ok: false;\n error: string;\n alt?: string;\n query?: string;\n};\n\nconst IMAGE_TOOL_NAMES = new Set(['ImageGen', 'SearchImage', 'ImportAsset']);\n\nfunction parseOutput(output: unknown): ImageAssetSuccess | ImageAssetFailure | undefined {\n if (typeof output !== 'object' || output === null || !('ok' in output)) {\n return undefined;\n }\n\n return output as ImageAssetSuccess | ImageAssetFailure;\n}\n\n/** Absolute asset URL, or chat `previewUrl` + site `publicPath` (filesystem saves). */\nfunction previewSrc(image: ImageAsset, host?: string): string | undefined {\n const absolute = image.url?.trim() || image.previewUrl?.trim();\n\n if (absolute) {\n return absolute;\n }\n\n const publicPath = image.publicPath?.trim();\n\n if (!publicPath || !host) {\n return undefined;\n }\n\n try {\n return new URL(publicPath, host).href;\n }\n catch {\n return undefined;\n }\n}\n\nfunction titlesFor(toolName: string, count: number): { idle: string; progress: string } {\n if (toolName === 'SearchImage') {\n if (count > 1) {\n return { progress: `Finding ${ count } photos`, idle: `Found ${ count } photos` };\n }\n\n return { progress: 'Finding photos', idle: 'Found photos' };\n }\n\n if (toolName === 'ImportAsset') {\n return { progress: 'Importing file', idle: 'Imported file' };\n }\n\n if (count > 1) {\n return { progress: `Generating ${ count } images`, idle: `Generated ${ count } images` };\n }\n\n return { progress: 'Generating image', idle: 'Generated image' };\n}\n\nfunction failureTitle(toolName: string): string {\n if (toolName === 'SearchImage') {\n return 'Couldn\\'t find photos';\n }\n\n if (toolName === 'ImportAsset') {\n return 'Couldn\\'t import file';\n }\n\n return 'Couldn\\'t generate the image';\n}\n\nfunction CreditCaption({ credit }: { credit: ImageCredit }) {\n const profileHref = credit.profileUrl.trim();\n const unsplashHref = credit.unsplashUrl.trim() || 'https://unsplash.com';\n\n return (\n <Text variant=\"xs\" className={ styles.credit }>\n Photo by\n { ' ' }\n <Show\n when={ profileHref }\n fallback={ <span>{ credit.name }</span> }\n >\n {href => (\n <a\n className={ styles.creditLink }\n href={ href }\n rel=\"noreferrer\"\n target=\"_blank\"\n >\n { credit.name }\n </a>\n )}\n </Show>\n { ' / ' }\n <a\n className={ styles.creditLink }\n href={ unsplashHref }\n rel=\"noreferrer\"\n target=\"_blank\"\n >\n Unsplash\n </a>\n </Text>\n );\n}\n\ntype ToolInput = {\n alt?: string;\n query?: string;\n count?: unknown;\n prompts?: Array<{ alt?: string }>;\n};\n\nexport type ImageAssetFanSlot = {\n key: string;\n src?: string;\n alt: string;\n};\n\nfunction uniqueLines(values: Array<string | undefined>): string[] {\n const seen = new Set<string>();\n const lines: string[] = [];\n\n for (const value of values) {\n const line = value?.trim();\n\n if (!line || seen.has(line)) {\n continue;\n }\n\n seen.add(line);\n lines.push(line);\n }\n\n return lines;\n}\n\n/** Per-image alts, one each. Falls back to a joined ` · ` string by splitting it. */\nfunction captionLines(args: {\n images: ImageAsset[];\n prompts?: Array<{ alt?: string }>;\n fallback: string;\n}): string[] {\n const fromImages = uniqueLines(args.images.map(image => image.alt));\n\n if (fromImages.length > 0) {\n return fromImages;\n }\n\n const fromPrompts = uniqueLines((args.prompts ?? []).map(item => item.alt));\n\n if (fromPrompts.length > 0) {\n return fromPrompts;\n }\n\n if (args.fallback.includes(' · ')) {\n return uniqueLines(args.fallback.split(' · '));\n }\n\n return args.fallback ? [args.fallback] : [];\n}\n\nfunction requestedCount(input: ToolInput | undefined): number {\n const prompts = input?.prompts?.length ?? 0;\n const count = typeof input?.count === 'number' && input.count > 0 ? input.count : 0;\n\n return Math.max(prompts, count, 1);\n}\n\nfunction uniqueCredits(images: readonly ImageAsset[]): ImageCredit[] {\n const seen = new Set<string>();\n const credits: ImageCredit[] = [];\n\n for (const image of images) {\n if (!image.credit) {\n continue;\n }\n\n const key = image.credit.profileUrl || image.credit.name;\n\n if (seen.has(key)) {\n continue;\n }\n\n seen.add(key);\n credits.push(image.credit);\n }\n\n return credits;\n}\n\nfunction FanFace({ slot }: { slot: ImageAssetFanSlot }) {\n if (!slot.src) {\n return null;\n }\n\n const src = slot.src;\n\n return (\n <Lightbox alt={ slot.alt } src={ src }>\n {(open: LightboxOpen) => (\n <Pressable\n aria-label={ `View ${ slot.alt }` }\n className={ styles.fanHit }\n onPress={ open }\n >\n <Image alt=\"\" className={ styles.fanImage } src={ src } />\n </Pressable>\n )}\n </Lightbox>\n );\n}\n\nexport function ImageAssetThumbFan({\n badge,\n slots,\n}: {\n badge?: 'loader' | 'error';\n slots: readonly ImageAssetFanSlot[];\n}) {\n return (\n <div\n className={ styles.fan }\n data-count={ slots.length }\n style={ { '--n': slots.length } as CSSProperties }\n >\n <For each={ slots }>\n {(slot, index, { isLast }) => (\n <div\n key={ slot.key }\n className={ styles.fanCard }\n style={ { '--i': index } as CSSProperties }\n >\n <FanFace slot={ slot } />\n <Show when={ isLast && badge === 'loader' }>\n <ProgressLoader aria-hidden className={ styles.loader } size={ 14 } />\n </Show>\n <Show when={ isLast && badge === 'error' }>\n <AttentionTriangle aria-hidden className={ styles.errorMark } size={ 16 } />\n </Show>\n </div>\n )}\n </For>\n </div>\n );\n}\n\nexport function ImageAssetCardTitle({\n failed,\n idle,\n live,\n progress,\n stalled,\n statusDetail,\n}: {\n failed: boolean;\n idle: string;\n live: boolean;\n progress: string;\n stalled: boolean;\n statusDetail?: string;\n}) {\n if (stalled) {\n return (\n <Text className={ styles.title } color=\"secondary\">\n { TOOL_INTERRUPTED_MESSAGE }\n </Text>\n );\n }\n\n if (live) {\n return (\n <Shimmer as=\"span\" className={ styles.title } duration={ 1 }>\n { progress }\n </Shimmer>\n );\n }\n\n if (failed) {\n return (\n <FailedToolTitleTooltip statusDetail={ statusDetail }>\n <Text className={ styles.title } color=\"secondary\" decoration=\"line-through\">\n { idle }\n </Text>\n </FailedToolTitleTooltip>\n );\n }\n\n return <Text className={ styles.title }>{ idle }</Text>;\n}\n\n/** Card for ImageGen / SearchImage — thumb row, or a plain shell row when nothing came back. */\nexport function ImageAssetTool({ part }: ToolRendererProps) {\n const toolName = getToolName(part);\n const { previewUrl } = useChat();\n const { live, stalled } = useToolProgress(part.state);\n\n if (!IMAGE_TOOL_NAMES.has(toolName)) {\n return null;\n }\n\n const state = part.state;\n const failure = getToolFailureRowState(part);\n const done = state === 'output-available';\n const output = done ? parseOutput(part.output) : undefined;\n const success = (output?.ok === true) ? output : undefined;\n const error = (output?.ok === false) ? output.error : failure.tooltip;\n const images = success?.images ?? [];\n const input = (typeof part.input === 'object' && part.input !== null)\n ? part.input as ToolInput\n : undefined;\n\n const outputAlt = (output && 'alt' in output && typeof output.alt === 'string')\n ? output.alt\n : undefined;\n const outputQuery = (output && 'query' in output && typeof output.query === 'string')\n ? output.query\n : undefined;\n // Prefer short alt (ImageGen); stock search falls back to search query — never the gen prompt.\n const fallback = (\n success?.alt\n || outputAlt\n || input?.alt\n || success?.query\n || outputQuery\n || input?.query\n || ''\n ).trim();\n\n const inProgress = isToolInvocationInProgress(state);\n const failedEmpty = !inProgress && images.length === 0;\n const total = images.length > 0 ? images.length : requestedCount(input);\n const titles = titlesFor(toolName, total);\n const lines = uniqueLines([\n ...captionLines({\n images,\n prompts: input?.prompts,\n fallback,\n }),\n ...images.flatMap(image => (previewSrc(image, previewUrl) ? [] : [image.path])),\n ]);\n const credits = uniqueCredits(images);\n const slots: ImageAssetFanSlot[] = failedEmpty\n ? [{ key: 'failed', alt: failureTitle(toolName) }]\n : images.length > 0\n ? images.map((image, index) => {\n const src = previewSrc(image, previewUrl);\n\n return {\n key: src || image.path || `image-${ index }`,\n src,\n alt: image.alt?.trim() || lines[index] || `Image ${ index + 1 }`,\n };\n })\n : Array.from({ length: total }, (_, index) => ({\n key: `placeholder-${ index }`,\n alt: lines[index] || titles.progress,\n }));\n\n return (\n <ToolShellCard\n aria-busy={ live }\n className={ shellStyles.tool }\n collapsible={ false }\n data-slot=\"image-asset-tool\"\n >\n <Box direction=\"row\" fullWidth gap=\"md\" padding=\"md\">\n <ImageAssetThumbFan\n badge={ live ? 'loader' : failedEmpty ? 'error' : undefined }\n slots={ slots }\n />\n <Box gap=\"xxs\" grow>\n <ImageAssetCardTitle\n failed={ !failedEmpty && Boolean(error) }\n idle={ failedEmpty ? failureTitle(toolName) : titles.idle }\n live={ live }\n progress={ titles.progress }\n stalled={ stalled }\n statusDetail={ error }\n />\n <Show when={ lines.length === 1 }>\n <Text className={ styles.caption } color=\"secondary\" variant=\"sm\">\n { lines[0] }\n </Text>\n </Show>\n <Show when={ lines.length > 1 }>\n <ul className={ styles.captions }>\n <For each={ lines }>\n {line => (\n <li key={ line }>\n <Text className={ styles.caption } color=\"secondary\" variant=\"sm\">\n { line }\n </Text>\n </li>\n )}\n </For>\n </ul>\n </Show>\n <Show when={ credits.length > 0 }>\n <div className={ styles.credits }>\n <For each={ credits }>\n {credit => (\n <CreditCaption\n key={ credit.profileUrl || credit.name }\n credit={ credit }\n />\n )}\n </For>\n </div>\n </Show>\n </Box>\n </Box>\n </ToolShellCard>\n );\n}\n"],"names":["IMAGE_TOOL_NAMES","parseOutput","output","previewSrc","image","host","absolute","publicPath","titlesFor","toolName","count","failureTitle","CreditCaption","credit","profileHref","unsplashHref","Text","styles","Show","href","_jsx","uniqueLines","values","seen","lines","value","line","captionLines","args","fromImages","fromPrompts","item","requestedCount","input","prompts","uniqueCredits","images","credits","key","FanFace","slot","src","Lightbox","open","Pressable","Image","ImageAssetThumbFan","badge","slots","For","index","isLast","ProgressLoader","AttentionTriangle","ImageAssetCardTitle","failed","idle","live","progress","stalled","statusDetail","TOOL_INTERRUPTED_MESSAGE","Shimmer","FailedToolTitleTooltip","ImageAssetTool","part","getToolName","previewUrl","useChat","useToolProgress","state","failure","getToolFailureRowState","success","error","outputAlt","outputQuery","fallback","failedEmpty","isToolInvocationInProgress","total","titles","_","ToolShellCard","shellStyles","Box","_jsxs"],"mappings":"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"}
@@ -68,7 +68,7 @@ function M({
68
68
  const h = a(l.headerLabel, s && l.headerLabelTruncate, "whitespace-nowrap");
69
69
  if (m)
70
70
  return /* @__PURE__ */ e(H, {
71
- color: "danger",
71
+ color: "secondary",
72
72
  className: h,
73
73
  children: o ?? P
74
74
  });
@@ -1 +1 @@
1
- {"version":3,"file":"ToolShell.js","sources":["../../../../src/chat/Tool/shell/ToolShell.tsx"],"sourcesContent":["import { Text } from '@reforma/components/Text';\nimport { ChevronDown } from '@reforma/icons/8';\nimport { cn, mergeRefs } from '@reforma/lib';\nimport {\n createContext,\n HTMLAttributes,\n use,\n useMemo,\n useRef,\n type ReactNode,\n type Ref,\n} from 'react';\nimport { mergeProps } from 'react-aria';\nimport { OverlayTriggerStateContext } from 'react-aria-components';\n\nimport {\n Collapsible,\n CollapsibleMotionContent,\n CollapsibleTrigger,\n useCollapsible,\n} from '../../../Collapsible';\nimport { Pressable } from '../../../Pressable';\nimport { Shimmer } from '../../../Shimmer';\nimport { Show } from '../../../Show';\nimport { TOOL_INTERRUPTED_MESSAGE } from '../helpers';\nimport { useToolProgress, type ToolProgressState } from './toolProgress';\nimport styles from './ToolShell.module.css';\nimport { FailedToolTitleTooltip, isFailedToolStatus, ToolShellStatusIcon } from './ToolShellStatusIcon';\n\ntype ToolShellContextValue = {\n collapsible: boolean;\n};\n\nconst ToolShellContext = createContext<ToolShellContextValue | null>(null);\n\nconst HEADER_TRIGGER_ATTR = 'data-tool-shell-header';\n\n/** Clicks on nested controls (e.g. file chips) must not toggle the collapsible header. */\nfunction isNestedHeaderInteractive(target: EventTarget | null, header: HTMLElement): boolean {\n if (!(target instanceof Element)) {\n return false;\n }\n\n const interactive = target.closest(\n 'a[href], input, textarea, select, [role=\"link\"]'\n ) ?? target.closest('button, [role=\"button\"]');\n\n if (!interactive || !header.contains(interactive)) {\n return false;\n }\n\n return !interactive.hasAttribute(HEADER_TRIGGER_ATTR);\n}\n\n/** Compact tool row chrome: summary row + optional body. Set `collapsible` on the root to enable disclosure. */\nexport type ToolShellProps = HTMLAttributes<HTMLDivElement> & {\n /** When true, root is a collapsible and the header is the trigger. Body still mounts via {@link ToolShellContent}. */\n collapsible?: boolean;\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n isDisabled?: boolean;\n};\n\nexport function ToolShell({\n collapsible = false,\n defaultOpen = false,\n open,\n onOpenChange,\n isDisabled,\n className,\n children,\n ...props\n}: ToolShellProps) {\n const context = useMemo(() => ({ collapsible }), [collapsible]);\n\n if (collapsible) {\n return (\n <ToolShellContext value={ context }>\n <Collapsible\n className={ cn(styles.root, className) }\n data-slot=\"tool\"\n defaultOpen={ defaultOpen }\n open={ open }\n onOpenChange={ onOpenChange }\n isDisabled={ isDisabled }\n { ...props }\n >\n {children}\n </Collapsible>\n </ToolShellContext>\n );\n }\n\n return (\n <ToolShellContext value={ context }>\n <div\n className={ cn(styles.root, className) }\n data-slot=\"tool\"\n { ...props }\n >\n {children}\n </div>\n </ToolShellContext>\n );\n}\n\nexport interface ToolShellHeaderProps extends Omit<HTMLAttributes<HTMLButtonElement>, 'title' | 'type'> {\n state: string;\n /** Idle label (secondary text). Shimmers with {@link titleInProgress} while the tool runs. */\n title?: string;\n /** In-progress label; defaults to `title` when omitted. */\n titleInProgress?: string;\n /** Override interrupted copy when the run ended mid-tool (defaults to {@link TOOL_INTERRUPTED_MESSAGE}). */\n titleInterrupted?: string;\n /** When false, the title stays static while the tool runs (default true). */\n shimmer?: boolean;\n /** Optional leading icon before the title (e.g. Agent). */\n icon?: ReactNode;\n /** Sits between the icon and the title. */\n beforeTitle?: ReactNode;\n /** Ellipsize a long title in the row. */\n truncateTitle?: boolean;\n /** Error or denial detail; shown in a tooltip on the struck title. */\n statusDetail?: string | undefined;\n /**\n * Strike the idle title. Defaults to the same signal as the muted status icon\n * (SDK error/denial, or a `statusDetail` logical failure).\n */\n failed?: boolean;\n /** Tool is waiting on the user (e.g. AskUserQuestion) — do not treat idle non-terminal as stalled. */\n awaitingUser?: boolean;\n /**\n * Whole row is pressable and shows the hover chevron. `onPress` runs a custom\n * action (subagent). Without it, a parent `PopoverTrigger` supplies the press\n * (file list). Ignored when the shell is collapsible.\n */\n onPress?: () => void;\n /** Show the chevron and accept press from context when `onPress` is omitted. */\n disclosure?: boolean;\n ref?: Ref<HTMLDivElement>;\n children?: ReactNode;\n}\n\ntype ToolShellHeaderTitleProps = {\n title?: string;\n titleInProgress?: string;\n titleInterrupted?: string;\n live: boolean;\n stalled: boolean;\n shimmer: boolean;\n failed: boolean;\n truncate?: boolean;\n statusDetail?: string;\n};\n\nfunction ToolShellHeaderTitle({\n title,\n titleInProgress,\n titleInterrupted,\n live,\n stalled,\n shimmer,\n failed,\n truncate,\n statusDetail,\n}: ToolShellHeaderTitleProps) {\n const labelClassName = cn(\n styles.headerLabel,\n truncate && styles.headerLabelTruncate,\n 'whitespace-nowrap'\n );\n\n if (stalled) {\n return (\n <Text color=\"danger\" className={ labelClassName }>\n {titleInterrupted ?? TOOL_INTERRUPTED_MESSAGE}\n </Text>\n );\n }\n\n const label = title ?? titleInProgress;\n\n if (!label) {\n return null;\n }\n\n const progressLabel = titleInProgress ?? label;\n\n if (live && shimmer) {\n return (\n <Shimmer as=\"span\" className={ labelClassName } duration={ 1 }>\n {progressLabel}\n </Shimmer>\n );\n }\n\n if (failed && !live) {\n const struck = (\n <Text\n decoration=\"line-through\"\n color=\"secondary\"\n className={ labelClassName }\n aria-label={ `${ label } failed` }\n >\n {label}\n </Text>\n );\n\n if (!statusDetail?.trim()) {\n return struck;\n }\n\n return (\n <FailedToolTitleTooltip statusDetail={ statusDetail }>\n {struck}\n </FailedToolTitleTooltip>\n );\n }\n\n return (\n <Text className={ labelClassName }>\n {live ? progressLabel : label}\n </Text>\n );\n}\n\ntype ToolShellHeaderViewProps = ToolShellHeaderProps & {\n progress: ToolProgressState;\n};\n\nfunction ToolShellHeaderStatic({\n state,\n title,\n titleInProgress,\n titleInterrupted,\n icon,\n beforeTitle,\n children,\n statusDetail,\n failed,\n truncateTitle,\n className,\n progress,\n shimmer,\n onPress,\n disclosure,\n ref,\n}: ToolShellHeaderViewProps) {\n const overlay = use(OverlayTriggerStateContext);\n const expanded = overlay?.isOpen === true;\n const pressable = onPress != null || disclosure === true;\n const { live, stalled } = progress;\n const detail = stalled\n ? (statusDetail?.trim() || TOOL_INTERRUPTED_MESSAGE)\n : statusDetail;\n const statusState = stalled ? 'output-error' : state;\n const titleFailed = failed ?? isFailedToolStatus(statusState, detail);\n const row = (\n <>\n <ToolShellStatusIcon\n icon={ icon }\n state={ statusState }\n statusDetail={ detail }\n className={ styles.headerIcon }\n />\n {beforeTitle}\n\n <ToolShellHeaderTitle\n title={ title }\n titleInProgress={ titleInProgress }\n titleInterrupted={ titleInterrupted }\n live={ live }\n stalled={ stalled }\n shimmer={ shimmer !== false }\n failed={ titleFailed }\n truncate={ truncateTitle }\n statusDetail={ detail }\n />\n {children}\n <Show when={ pressable }>\n <ChevronDown\n className={ cn('chevron', 'next', styles.toolChevron) }\n aria-expanded={ overlay ? expanded : undefined }\n aria-hidden\n />\n </Show>\n </>\n );\n\n if (pressable) {\n return (\n <Pressable ref={ ref } { ...(onPress ? { onPress } : {}) }>\n <div\n role=\"button\"\n className={ cn(styles.headerRow, styles.headerTrigger, className) }\n aria-busy={ live }\n aria-expanded={ overlay ? expanded : undefined }\n >\n {row}\n </div>\n </Pressable>\n );\n }\n\n return (\n <div\n className={ cn(styles.headerRow, styles.headerNonInteractive, className) }\n aria-busy={ live }\n >\n {row}\n </div>\n );\n}\n\nfunction ToolShellHeaderCollapsible({\n state,\n title,\n titleInProgress,\n titleInterrupted,\n icon,\n beforeTitle,\n children,\n statusDetail,\n failed,\n truncateTitle,\n className,\n progress,\n shimmer,\n}: ToolShellHeaderViewProps) {\n const { state: collapsibleState, triggerProps, triggerRef } = useCollapsible();\n const headerRef = useRef<HTMLDivElement>(null);\n const { live, stalled } = progress;\n const detail = stalled\n ? (statusDetail?.trim() || TOOL_INTERRUPTED_MESSAGE)\n : statusDetail;\n const statusState = stalled ? 'output-error' : state;\n const titleFailed = failed ?? isFailedToolStatus(statusState, detail);\n\n const triggerOnPress = (triggerProps as { onPress?: (event: { target: EventTarget }) => void }).onPress;\n\n // eslint-disable-next-line react-hooks/refs -- mergeRefs composes; it does not read `.current`\n const hostProps = mergeProps(triggerProps, {\n [HEADER_TRIGGER_ATTR]: '',\n className: cn(styles.headerRow, styles.headerTrigger, className),\n // eslint-disable-next-line react-hooks/refs -- mergeRefs composes; it does not read `.current`\n ref: mergeRefs(triggerRef, headerRef),\n 'aria-busy': live,\n 'aria-expanded': collapsibleState.isExpanded,\n onPress: (event: { target: EventTarget }) => {\n const header = headerRef.current;\n\n if (header && isNestedHeaderInteractive(event.target, header)) {\n return;\n }\n\n triggerOnPress?.(event);\n },\n });\n\n return (\n <CollapsibleTrigger asChild>\n <div { ...(hostProps as HTMLAttributes<HTMLDivElement>) }>\n <ToolShellStatusIcon\n icon={ icon }\n state={ statusState }\n statusDetail={ detail }\n className={ styles.headerIcon }\n />\n {beforeTitle}\n\n <ToolShellHeaderTitle\n title={ title }\n titleInProgress={ titleInProgress }\n titleInterrupted={ titleInterrupted }\n live={ live }\n stalled={ stalled }\n shimmer={ shimmer !== false }\n failed={ titleFailed }\n truncate={ truncateTitle }\n statusDetail={ detail }\n />\n {children}\n\n <ChevronDown\n className={ cn('chevron', 'next', styles.toolChevron) }\n aria-expanded={ collapsibleState.isExpanded }\n aria-hidden\n />\n </div>\n </CollapsibleTrigger>\n );\n}\n\nexport function ToolShellHeader(props: ToolShellHeaderProps) {\n const shell = use(ToolShellContext);\n const progress = useToolProgress(props.state, props.awaitingUser);\n\n if (shell?.collapsible) {\n return <ToolShellHeaderCollapsible { ...props } progress={ progress } />;\n }\n\n return <ToolShellHeaderStatic { ...props } progress={ progress } />;\n}\n\nexport type ToolShellContentProps = HTMLAttributes<HTMLDivElement>;\n\nfunction ToolShellContentStatic({ className, children, ...props }: ToolShellContentProps) {\n return (\n <div className={ cn(styles.content, className) } data-slot=\"tool-content\" { ...props }>\n {children}\n </div>\n );\n}\n\nfunction ToolShellContentCollapsible({ className, children, ...props }: ToolShellContentProps) {\n return (\n <CollapsibleMotionContent className={ styles.collapse }>\n <div className={ cn(styles.content, className) } data-slot=\"tool-content\" { ...props }>\n {children}\n </div>\n </CollapsibleMotionContent>\n );\n}\n\nexport function ToolShellContent({ className, children, ...props }: ToolShellContentProps) {\n const shell = use(ToolShellContext);\n\n if (shell?.collapsible) {\n return (\n <ToolShellContentCollapsible className={ className } { ...props }>\n {children}\n </ToolShellContentCollapsible>\n );\n }\n\n return (\n <ToolShellContentStatic className={ className } { ...props }>\n {children}\n </ToolShellContentStatic>\n );\n}\n\nexport type ToolShellFooterProps = HTMLAttributes<HTMLDivElement>;\n\nexport function ToolShellFooter({ className, children, ...props }: ToolShellFooterProps) {\n return (\n <div className={ cn(styles.footer, className) } data-slot=\"tool-footer\" { ...props }>\n {children}\n </div>\n );\n}\n"],"names":["ToolShellContext","HEADER_TRIGGER_ATTR","isNestedHeaderInteractive","target","header","interactive","ToolShell","collapsible","defaultOpen","open","onOpenChange","isDisabled","className","children","props","context","useMemo","Collapsible","cn","styles","ToolShellHeaderTitle","title","titleInProgress","titleInterrupted","live","stalled","shimmer","failed","truncate","statusDetail","labelClassName","Text","TOOL_INTERRUPTED_MESSAGE","label","progressLabel","Shimmer","struck","FailedToolTitleTooltip","ToolShellHeaderStatic","state","icon","beforeTitle","truncateTitle","progress","onPress","disclosure","ref","overlay","use","OverlayTriggerStateContext","expanded","pressable","detail","statusState","titleFailed","isFailedToolStatus","row","_Fragment","_jsx","ToolShellStatusIcon","Show","ChevronDown","Pressable","ToolShellHeaderCollapsible","collapsibleState","triggerProps","triggerRef","useCollapsible","headerRef","useRef","triggerOnPress","hostProps","mergeProps","mergeRefs","event","CollapsibleTrigger","ToolShellHeader","shell","useToolProgress","ToolShellContentStatic","ToolShellContentCollapsible","CollapsibleMotionContent","ToolShellContent","ToolShellFooter"],"mappings":"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"}
1
+ {"version":3,"file":"ToolShell.js","sources":["../../../../src/chat/Tool/shell/ToolShell.tsx"],"sourcesContent":["import { Text } from '@reforma/components/Text';\nimport { ChevronDown } from '@reforma/icons/8';\nimport { cn, mergeRefs } from '@reforma/lib';\nimport {\n createContext,\n HTMLAttributes,\n use,\n useMemo,\n useRef,\n type ReactNode,\n type Ref,\n} from 'react';\nimport { mergeProps } from 'react-aria';\nimport { OverlayTriggerStateContext } from 'react-aria-components';\n\nimport {\n Collapsible,\n CollapsibleMotionContent,\n CollapsibleTrigger,\n useCollapsible,\n} from '../../../Collapsible';\nimport { Pressable } from '../../../Pressable';\nimport { Shimmer } from '../../../Shimmer';\nimport { Show } from '../../../Show';\nimport { TOOL_INTERRUPTED_MESSAGE } from '../helpers';\nimport { useToolProgress, type ToolProgressState } from './toolProgress';\nimport styles from './ToolShell.module.css';\nimport { FailedToolTitleTooltip, isFailedToolStatus, ToolShellStatusIcon } from './ToolShellStatusIcon';\n\ntype ToolShellContextValue = {\n collapsible: boolean;\n};\n\nconst ToolShellContext = createContext<ToolShellContextValue | null>(null);\n\nconst HEADER_TRIGGER_ATTR = 'data-tool-shell-header';\n\n/** Clicks on nested controls (e.g. file chips) must not toggle the collapsible header. */\nfunction isNestedHeaderInteractive(target: EventTarget | null, header: HTMLElement): boolean {\n if (!(target instanceof Element)) {\n return false;\n }\n\n const interactive = target.closest(\n 'a[href], input, textarea, select, [role=\"link\"]'\n ) ?? target.closest('button, [role=\"button\"]');\n\n if (!interactive || !header.contains(interactive)) {\n return false;\n }\n\n return !interactive.hasAttribute(HEADER_TRIGGER_ATTR);\n}\n\n/** Compact tool row chrome: summary row + optional body. Set `collapsible` on the root to enable disclosure. */\nexport type ToolShellProps = HTMLAttributes<HTMLDivElement> & {\n /** When true, root is a collapsible and the header is the trigger. Body still mounts via {@link ToolShellContent}. */\n collapsible?: boolean;\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n isDisabled?: boolean;\n};\n\nexport function ToolShell({\n collapsible = false,\n defaultOpen = false,\n open,\n onOpenChange,\n isDisabled,\n className,\n children,\n ...props\n}: ToolShellProps) {\n const context = useMemo(() => ({ collapsible }), [collapsible]);\n\n if (collapsible) {\n return (\n <ToolShellContext value={ context }>\n <Collapsible\n className={ cn(styles.root, className) }\n data-slot=\"tool\"\n defaultOpen={ defaultOpen }\n open={ open }\n onOpenChange={ onOpenChange }\n isDisabled={ isDisabled }\n { ...props }\n >\n {children}\n </Collapsible>\n </ToolShellContext>\n );\n }\n\n return (\n <ToolShellContext value={ context }>\n <div\n className={ cn(styles.root, className) }\n data-slot=\"tool\"\n { ...props }\n >\n {children}\n </div>\n </ToolShellContext>\n );\n}\n\nexport interface ToolShellHeaderProps extends Omit<HTMLAttributes<HTMLButtonElement>, 'title' | 'type'> {\n state: string;\n /** Idle label (secondary text). Shimmers with {@link titleInProgress} while the tool runs. */\n title?: string;\n /** In-progress label; defaults to `title` when omitted. */\n titleInProgress?: string;\n /** Override interrupted copy when the run ended mid-tool (defaults to {@link TOOL_INTERRUPTED_MESSAGE}). */\n titleInterrupted?: string;\n /** When false, the title stays static while the tool runs (default true). */\n shimmer?: boolean;\n /** Optional leading icon before the title (e.g. Agent). */\n icon?: ReactNode;\n /** Sits between the icon and the title. */\n beforeTitle?: ReactNode;\n /** Ellipsize a long title in the row. */\n truncateTitle?: boolean;\n /** Error or denial detail; shown in a tooltip on the struck title. */\n statusDetail?: string | undefined;\n /**\n * Strike the idle title. Defaults to the same signal as the muted status icon\n * (SDK error/denial, or a `statusDetail` logical failure).\n */\n failed?: boolean;\n /** Tool is waiting on the user (e.g. AskUserQuestion) — do not treat idle non-terminal as stalled. */\n awaitingUser?: boolean;\n /**\n * Whole row is pressable and shows the hover chevron. `onPress` runs a custom\n * action (subagent). Without it, a parent `PopoverTrigger` supplies the press\n * (file list). Ignored when the shell is collapsible.\n */\n onPress?: () => void;\n /** Show the chevron and accept press from context when `onPress` is omitted. */\n disclosure?: boolean;\n ref?: Ref<HTMLDivElement>;\n children?: ReactNode;\n}\n\ntype ToolShellHeaderTitleProps = {\n title?: string;\n titleInProgress?: string;\n titleInterrupted?: string;\n live: boolean;\n stalled: boolean;\n shimmer: boolean;\n failed: boolean;\n truncate?: boolean;\n statusDetail?: string;\n};\n\nfunction ToolShellHeaderTitle({\n title,\n titleInProgress,\n titleInterrupted,\n live,\n stalled,\n shimmer,\n failed,\n truncate,\n statusDetail,\n}: ToolShellHeaderTitleProps) {\n const labelClassName = cn(\n styles.headerLabel,\n truncate && styles.headerLabelTruncate,\n 'whitespace-nowrap'\n );\n\n if (stalled) {\n return (\n <Text color=\"secondary\" className={ labelClassName }>\n {titleInterrupted ?? TOOL_INTERRUPTED_MESSAGE}\n </Text>\n );\n }\n\n const label = title ?? titleInProgress;\n\n if (!label) {\n return null;\n }\n\n const progressLabel = titleInProgress ?? label;\n\n if (live && shimmer) {\n return (\n <Shimmer as=\"span\" className={ labelClassName } duration={ 1 }>\n {progressLabel}\n </Shimmer>\n );\n }\n\n if (failed && !live) {\n const struck = (\n <Text\n decoration=\"line-through\"\n color=\"secondary\"\n className={ labelClassName }\n aria-label={ `${ label } failed` }\n >\n {label}\n </Text>\n );\n\n if (!statusDetail?.trim()) {\n return struck;\n }\n\n return (\n <FailedToolTitleTooltip statusDetail={ statusDetail }>\n {struck}\n </FailedToolTitleTooltip>\n );\n }\n\n return (\n <Text className={ labelClassName }>\n {live ? progressLabel : label}\n </Text>\n );\n}\n\ntype ToolShellHeaderViewProps = ToolShellHeaderProps & {\n progress: ToolProgressState;\n};\n\nfunction ToolShellHeaderStatic({\n state,\n title,\n titleInProgress,\n titleInterrupted,\n icon,\n beforeTitle,\n children,\n statusDetail,\n failed,\n truncateTitle,\n className,\n progress,\n shimmer,\n onPress,\n disclosure,\n ref,\n}: ToolShellHeaderViewProps) {\n const overlay = use(OverlayTriggerStateContext);\n const expanded = overlay?.isOpen === true;\n const pressable = onPress != null || disclosure === true;\n const { live, stalled } = progress;\n const detail = stalled\n ? (statusDetail?.trim() || TOOL_INTERRUPTED_MESSAGE)\n : statusDetail;\n const statusState = stalled ? 'output-error' : state;\n const titleFailed = failed ?? isFailedToolStatus(statusState, detail);\n const row = (\n <>\n <ToolShellStatusIcon\n icon={ icon }\n state={ statusState }\n statusDetail={ detail }\n className={ styles.headerIcon }\n />\n {beforeTitle}\n\n <ToolShellHeaderTitle\n title={ title }\n titleInProgress={ titleInProgress }\n titleInterrupted={ titleInterrupted }\n live={ live }\n stalled={ stalled }\n shimmer={ shimmer !== false }\n failed={ titleFailed }\n truncate={ truncateTitle }\n statusDetail={ detail }\n />\n {children}\n <Show when={ pressable }>\n <ChevronDown\n className={ cn('chevron', 'next', styles.toolChevron) }\n aria-expanded={ overlay ? expanded : undefined }\n aria-hidden\n />\n </Show>\n </>\n );\n\n if (pressable) {\n return (\n <Pressable ref={ ref } { ...(onPress ? { onPress } : {}) }>\n <div\n role=\"button\"\n className={ cn(styles.headerRow, styles.headerTrigger, className) }\n aria-busy={ live }\n aria-expanded={ overlay ? expanded : undefined }\n >\n {row}\n </div>\n </Pressable>\n );\n }\n\n return (\n <div\n className={ cn(styles.headerRow, styles.headerNonInteractive, className) }\n aria-busy={ live }\n >\n {row}\n </div>\n );\n}\n\nfunction ToolShellHeaderCollapsible({\n state,\n title,\n titleInProgress,\n titleInterrupted,\n icon,\n beforeTitle,\n children,\n statusDetail,\n failed,\n truncateTitle,\n className,\n progress,\n shimmer,\n}: ToolShellHeaderViewProps) {\n const { state: collapsibleState, triggerProps, triggerRef } = useCollapsible();\n const headerRef = useRef<HTMLDivElement>(null);\n const { live, stalled } = progress;\n const detail = stalled\n ? (statusDetail?.trim() || TOOL_INTERRUPTED_MESSAGE)\n : statusDetail;\n const statusState = stalled ? 'output-error' : state;\n const titleFailed = failed ?? isFailedToolStatus(statusState, detail);\n\n const triggerOnPress = (triggerProps as { onPress?: (event: { target: EventTarget }) => void }).onPress;\n\n // eslint-disable-next-line react-hooks/refs -- mergeRefs composes; it does not read `.current`\n const hostProps = mergeProps(triggerProps, {\n [HEADER_TRIGGER_ATTR]: '',\n className: cn(styles.headerRow, styles.headerTrigger, className),\n // eslint-disable-next-line react-hooks/refs -- mergeRefs composes; it does not read `.current`\n ref: mergeRefs(triggerRef, headerRef),\n 'aria-busy': live,\n 'aria-expanded': collapsibleState.isExpanded,\n onPress: (event: { target: EventTarget }) => {\n const header = headerRef.current;\n\n if (header && isNestedHeaderInteractive(event.target, header)) {\n return;\n }\n\n triggerOnPress?.(event);\n },\n });\n\n return (\n <CollapsibleTrigger asChild>\n <div { ...(hostProps as HTMLAttributes<HTMLDivElement>) }>\n <ToolShellStatusIcon\n icon={ icon }\n state={ statusState }\n statusDetail={ detail }\n className={ styles.headerIcon }\n />\n {beforeTitle}\n\n <ToolShellHeaderTitle\n title={ title }\n titleInProgress={ titleInProgress }\n titleInterrupted={ titleInterrupted }\n live={ live }\n stalled={ stalled }\n shimmer={ shimmer !== false }\n failed={ titleFailed }\n truncate={ truncateTitle }\n statusDetail={ detail }\n />\n {children}\n\n <ChevronDown\n className={ cn('chevron', 'next', styles.toolChevron) }\n aria-expanded={ collapsibleState.isExpanded }\n aria-hidden\n />\n </div>\n </CollapsibleTrigger>\n );\n}\n\nexport function ToolShellHeader(props: ToolShellHeaderProps) {\n const shell = use(ToolShellContext);\n const progress = useToolProgress(props.state, props.awaitingUser);\n\n if (shell?.collapsible) {\n return <ToolShellHeaderCollapsible { ...props } progress={ progress } />;\n }\n\n return <ToolShellHeaderStatic { ...props } progress={ progress } />;\n}\n\nexport type ToolShellContentProps = HTMLAttributes<HTMLDivElement>;\n\nfunction ToolShellContentStatic({ className, children, ...props }: ToolShellContentProps) {\n return (\n <div className={ cn(styles.content, className) } data-slot=\"tool-content\" { ...props }>\n {children}\n </div>\n );\n}\n\nfunction ToolShellContentCollapsible({ className, children, ...props }: ToolShellContentProps) {\n return (\n <CollapsibleMotionContent className={ styles.collapse }>\n <div className={ cn(styles.content, className) } data-slot=\"tool-content\" { ...props }>\n {children}\n </div>\n </CollapsibleMotionContent>\n );\n}\n\nexport function ToolShellContent({ className, children, ...props }: ToolShellContentProps) {\n const shell = use(ToolShellContext);\n\n if (shell?.collapsible) {\n return (\n <ToolShellContentCollapsible className={ className } { ...props }>\n {children}\n </ToolShellContentCollapsible>\n );\n }\n\n return (\n <ToolShellContentStatic className={ className } { ...props }>\n {children}\n </ToolShellContentStatic>\n );\n}\n\nexport type ToolShellFooterProps = HTMLAttributes<HTMLDivElement>;\n\nexport function ToolShellFooter({ className, children, ...props }: ToolShellFooterProps) {\n return (\n <div className={ cn(styles.footer, className) } data-slot=\"tool-footer\" { ...props }>\n {children}\n </div>\n );\n}\n"],"names":["ToolShellContext","HEADER_TRIGGER_ATTR","isNestedHeaderInteractive","target","header","interactive","ToolShell","collapsible","defaultOpen","open","onOpenChange","isDisabled","className","children","props","context","useMemo","Collapsible","cn","styles","ToolShellHeaderTitle","title","titleInProgress","titleInterrupted","live","stalled","shimmer","failed","truncate","statusDetail","labelClassName","Text","TOOL_INTERRUPTED_MESSAGE","label","progressLabel","Shimmer","struck","FailedToolTitleTooltip","ToolShellHeaderStatic","state","icon","beforeTitle","truncateTitle","progress","onPress","disclosure","ref","overlay","use","OverlayTriggerStateContext","expanded","pressable","detail","statusState","titleFailed","isFailedToolStatus","row","_Fragment","_jsx","ToolShellStatusIcon","Show","ChevronDown","Pressable","ToolShellHeaderCollapsible","collapsibleState","triggerProps","triggerRef","useCollapsible","headerRef","useRef","triggerOnPress","hostProps","mergeProps","mergeRefs","event","CollapsibleTrigger","ToolShellHeader","shell","useToolProgress","ToolShellContentStatic","ToolShellContentCollapsible","CollapsibleMotionContent","ToolShellContent","ToolShellFooter"],"mappings":"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"}
@@ -7,7 +7,7 @@ import { Shimmer as j } from "../../../Shimmer/Shimmer.js";
7
7
  import { TOOL_INTERRUPTED_MESSAGE as b } from "../helpers.js";
8
8
  import { useToolProgress as w } from "./toolProgress.js";
9
9
  import a from "./ToolShellCard.module.css.js";
10
- import { isFailedToolStatus as v, ToolShellStatusIcon as g, FailedToolTitleTooltip as D } from "./ToolShellStatusIcon.js";
10
+ import { isFailedToolStatus as v, ToolShellStatusIcon as y, FailedToolTitleTooltip as D } from "./ToolShellStatusIcon.js";
11
11
  import { jsx as o, jsxs as S } from "react/jsx-runtime";
12
12
  const p = /* @__PURE__ */ I(null);
13
13
  function W({
@@ -45,10 +45,10 @@ function W({
45
45
  })
46
46
  });
47
47
  }
48
- function y(e, t, r, n, i) {
48
+ function g(e, t, r, n, i) {
49
49
  if (r)
50
50
  return e != null && typeof e != "string" && typeof e != "number" ? e : /* @__PURE__ */ o(C, {
51
- color: "danger",
51
+ color: "secondary",
52
52
  className: "truncate",
53
53
  children: typeof e == "string" || typeof e == "number" ? String(e) : b
54
54
  });
@@ -96,12 +96,12 @@ function O({
96
96
  "aria-busy": u,
97
97
  children: [/* @__PURE__ */ S("div", {
98
98
  className: a.headerMain,
99
- children: [/* @__PURE__ */ o(g, {
99
+ children: [/* @__PURE__ */ o(y, {
100
100
  icon: r,
101
101
  state: h,
102
102
  statusDetail: m,
103
103
  className: a.headerIcon
104
- }), y(t, u, l, f, m)]
104
+ }), g(t, u, l, f, m)]
105
105
  }), d]
106
106
  });
107
107
  }
@@ -131,12 +131,12 @@ function P({
131
131
  ...u,
132
132
  children: [/* @__PURE__ */ S("div", {
133
133
  className: a.headerMain,
134
- children: [/* @__PURE__ */ o(g, {
134
+ children: [/* @__PURE__ */ o(y, {
135
135
  icon: r,
136
136
  state: T,
137
137
  statusDetail: f,
138
138
  className: a.headerIcon
139
- }), y(t, m, h, x, f)]
139
+ }), g(t, m, h, x, f)]
140
140
  }), /* @__PURE__ */ o(E, {
141
141
  className: s("chevron", "next", a.toolChevron),
142
142
  "aria-expanded": l.isExpanded,
@@ -1 +1 @@
1
- {"version":3,"file":"ToolShellCard.js","sources":["../../../../src/chat/Tool/shell/ToolShellCard.tsx"],"sourcesContent":["import { Text } from '@reforma/components/Text';\nimport { ChevronDown } from '@reforma/icons/8';\nimport { cn } from '@reforma/lib';\nimport { createContext, HTMLAttributes, use, useMemo, type ReactNode } from 'react';\n\nimport {\n Collapsible,\n CollapsibleMotionContent,\n CollapsibleTrigger,\n useCollapsible,\n} from '../../../Collapsible';\nimport { Shimmer } from '../../../Shimmer';\nimport { TOOL_INTERRUPTED_MESSAGE } from '../helpers';\nimport { useToolProgress, type ToolProgressState } from './toolProgress';\nimport styles from './ToolShellCard.module.css';\nimport { FailedToolTitleTooltip, isFailedToolStatus, ToolShellStatusIcon } from './ToolShellStatusIcon';\n\ntype ToolShellCardContextValue = {\n collapsible: boolean;\n};\n\nconst ToolShellCardContext = createContext<ToolShellCardContextValue | null>(null);\n\n/** Boxed tool card chrome. Set `collapsible` on the root to enable disclosure. */\nexport type ToolShellCardProps = HTMLAttributes<HTMLDivElement> & {\n /** When true, root is a collapsible and the header is the trigger. */\n collapsible?: boolean;\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n isDisabled?: boolean;\n};\n\nexport function ToolShellCard({\n collapsible = true,\n defaultOpen = false,\n open,\n onOpenChange,\n isDisabled,\n className,\n children,\n ...props\n}: ToolShellCardProps) {\n const context = useMemo(() => ({ collapsible }), [collapsible]);\n\n if (collapsible) {\n return (\n <ToolShellCardContext value={ context }>\n <Collapsible\n className={ cn(styles.root, className) }\n data-slot=\"tool-card\"\n defaultOpen={ defaultOpen }\n open={ open }\n onOpenChange={ onOpenChange }\n isDisabled={ isDisabled }\n { ...props }\n >\n {children}\n </Collapsible>\n </ToolShellCardContext>\n );\n }\n\n return (\n <ToolShellCardContext value={ context }>\n <div\n className={ cn(styles.root, className) }\n data-slot=\"tool-card\"\n { ...props }\n >\n {children}\n </div>\n </ToolShellCardContext>\n );\n}\n\nexport interface ToolShellCardHeaderProps extends Omit<HTMLAttributes<HTMLButtonElement>, 'title' | 'type'> {\n state: string;\n title?: ReactNode;\n /** Optional leading icon before the title (e.g. proxied MCP tools). */\n icon?: ReactNode;\n /** Error or denial detail; shown in a tooltip on the struck title. */\n statusDetail?: string | undefined;\n /** Tool is waiting on the user — do not treat idle non-terminal as stalled. */\n awaitingUser?: boolean;\n}\n\nfunction toolShellCardHeaderLabel(\n title: ReactNode | undefined,\n live: boolean,\n stalled: boolean,\n failed: boolean,\n statusDetail?: string\n): ReactNode {\n if (stalled) {\n if (title != null && typeof title !== 'string' && typeof title !== 'number') {\n return title;\n }\n\n return (\n <Text color=\"danger\" className=\"truncate\">\n { (typeof title === 'string' || typeof title === 'number')\n ? String(title)\n : TOOL_INTERRUPTED_MESSAGE}\n </Text>\n );\n }\n\n if (title != null && typeof title !== 'string' && typeof title !== 'number') {\n return title;\n }\n\n const canShimmerLabel = typeof title === 'string' || typeof title === 'number';\n\n if (live && canShimmerLabel) {\n return (\n <Shimmer duration={ 1 } className=\"truncate\">\n {String(title)}\n </Shimmer>\n );\n }\n\n if (failed) {\n const label = title == null ? '' : String(title);\n\n return (\n <FailedToolTitleTooltip statusDetail={ statusDetail }>\n <Text\n decoration=\"line-through\"\n color=\"secondary\"\n className=\"truncate\"\n aria-label={ `${ label } failed` }\n >\n {title}\n </Text>\n </FailedToolTitleTooltip>\n );\n }\n\n return (\n <Text className=\"truncate\">{title}</Text>\n );\n}\n\ntype ToolShellCardHeaderViewProps = ToolShellCardHeaderProps & {\n progress: ToolProgressState;\n};\n\nfunction ToolShellCardHeaderStatic({\n state,\n title,\n icon,\n statusDetail,\n className,\n progress,\n children,\n}: ToolShellCardHeaderViewProps) {\n const { live, stalled } = progress;\n const detail = stalled\n ? (statusDetail?.trim() || TOOL_INTERRUPTED_MESSAGE)\n : statusDetail;\n const statusState = stalled ? 'output-error' : state;\n const titleFailed = isFailedToolStatus(statusState, detail);\n\n return (\n <div\n className={ cn(styles.headerNonInteractive, className) }\n aria-busy={ live }\n >\n <div className={ styles.headerMain }>\n <ToolShellStatusIcon\n icon={ icon }\n state={ statusState }\n statusDetail={ detail }\n className={ styles.headerIcon }\n />\n {toolShellCardHeaderLabel(title, live, stalled, titleFailed, detail)}\n </div>\n {children}\n </div>\n );\n}\n\nfunction ToolShellCardHeaderCollapsible({\n state,\n title,\n icon,\n statusDetail,\n className,\n progress,\n children: _children,\n ...props\n}: ToolShellCardHeaderViewProps) {\n const { state: collapsibleState } = useCollapsible();\n const { live, stalled } = progress;\n const detail = stalled\n ? (statusDetail?.trim() || TOOL_INTERRUPTED_MESSAGE)\n : statusDetail;\n const statusState = stalled ? 'output-error' : state;\n const titleFailed = isFailedToolStatus(statusState, detail);\n\n return (\n <CollapsibleTrigger asChild>\n <button\n type=\"button\"\n className={ cn(styles.header, className) }\n aria-busy={ live }\n aria-expanded={ collapsibleState.isExpanded }\n { ...props }\n >\n <div className={ styles.headerMain }>\n <ToolShellStatusIcon\n icon={ icon }\n state={ statusState }\n statusDetail={ detail }\n className={ styles.headerIcon }\n />\n {toolShellCardHeaderLabel(title, live, stalled, titleFailed, detail)}\n </div>\n\n <ChevronDown\n className={ cn('chevron', 'next', styles.toolChevron) }\n aria-expanded={ collapsibleState.isExpanded }\n aria-hidden\n />\n </button>\n </CollapsibleTrigger>\n );\n}\n\nexport function ToolShellCardHeader(props: ToolShellCardHeaderProps) {\n const shell = use(ToolShellCardContext);\n const progress = useToolProgress(props.state, props.awaitingUser);\n\n if (shell?.collapsible) {\n return <ToolShellCardHeaderCollapsible { ...props } progress={ progress } />;\n }\n\n return <ToolShellCardHeaderStatic { ...props } progress={ progress } />;\n}\n\nexport type ToolShellCardContentProps = HTMLAttributes<HTMLDivElement>;\n\nfunction ToolShellCardContentStatic({ className, children, ...props }: ToolShellCardContentProps) {\n return (\n <div className={ cn(styles.content, className) } data-slot=\"tool-card-content\" { ...props }>\n {children}\n </div>\n );\n}\n\nfunction ToolShellCardContentCollapsible({ className, children, ...props }: ToolShellCardContentProps) {\n return (\n <CollapsibleMotionContent>\n <div className={ cn(styles.content, className) } data-slot=\"tool-card-content\" { ...props }>\n {children}\n </div>\n </CollapsibleMotionContent>\n );\n}\n\nexport function ToolShellCardContent({ className, children, ...props }: ToolShellCardContentProps) {\n const shell = use(ToolShellCardContext);\n\n if (shell?.collapsible) {\n return (\n <ToolShellCardContentCollapsible className={ className } { ...props }>\n {children}\n </ToolShellCardContentCollapsible>\n );\n }\n\n return (\n <ToolShellCardContentStatic className={ className } { ...props }>\n {children}\n </ToolShellCardContentStatic>\n );\n}\n\nexport type ToolShellCardFooterProps = HTMLAttributes<HTMLDivElement>;\n\n/** Footer strip for tool errors and approval flows. */\nexport function ToolShellCardFooter({ className, children, ...props }: ToolShellCardFooterProps) {\n return (\n <div className={ cn(styles.footer, className) } data-slot=\"tool-card-footer\" { ...props }>\n {children}\n </div>\n );\n}\n"],"names":["ToolShellCardContext","ToolShellCard","collapsible","defaultOpen","open","onOpenChange","isDisabled","className","children","props","context","useMemo","Collapsible","cn","styles","toolShellCardHeaderLabel","title","live","stalled","failed","statusDetail","Text","TOOL_INTERRUPTED_MESSAGE","Shimmer","label","FailedToolTitleTooltip","ToolShellCardHeaderStatic","state","icon","progress","detail","statusState","titleFailed","isFailedToolStatus","_jsxs","_jsx","ToolShellStatusIcon","ToolShellCardHeaderCollapsible","_children","collapsibleState","useCollapsible","CollapsibleTrigger","ChevronDown","ToolShellCardHeader","shell","use","useToolProgress","ToolShellCardContentStatic","ToolShellCardContentCollapsible","CollapsibleMotionContent","ToolShellCardContent","ToolShellCardFooter"],"mappings":"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"}
1
+ {"version":3,"file":"ToolShellCard.js","sources":["../../../../src/chat/Tool/shell/ToolShellCard.tsx"],"sourcesContent":["import { Text } from '@reforma/components/Text';\nimport { ChevronDown } from '@reforma/icons/8';\nimport { cn } from '@reforma/lib';\nimport { createContext, HTMLAttributes, use, useMemo, type ReactNode } from 'react';\n\nimport {\n Collapsible,\n CollapsibleMotionContent,\n CollapsibleTrigger,\n useCollapsible,\n} from '../../../Collapsible';\nimport { Shimmer } from '../../../Shimmer';\nimport { TOOL_INTERRUPTED_MESSAGE } from '../helpers';\nimport { useToolProgress, type ToolProgressState } from './toolProgress';\nimport styles from './ToolShellCard.module.css';\nimport { FailedToolTitleTooltip, isFailedToolStatus, ToolShellStatusIcon } from './ToolShellStatusIcon';\n\ntype ToolShellCardContextValue = {\n collapsible: boolean;\n};\n\nconst ToolShellCardContext = createContext<ToolShellCardContextValue | null>(null);\n\n/** Boxed tool card chrome. Set `collapsible` on the root to enable disclosure. */\nexport type ToolShellCardProps = HTMLAttributes<HTMLDivElement> & {\n /** When true, root is a collapsible and the header is the trigger. */\n collapsible?: boolean;\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n isDisabled?: boolean;\n};\n\nexport function ToolShellCard({\n collapsible = true,\n defaultOpen = false,\n open,\n onOpenChange,\n isDisabled,\n className,\n children,\n ...props\n}: ToolShellCardProps) {\n const context = useMemo(() => ({ collapsible }), [collapsible]);\n\n if (collapsible) {\n return (\n <ToolShellCardContext value={ context }>\n <Collapsible\n className={ cn(styles.root, className) }\n data-slot=\"tool-card\"\n defaultOpen={ defaultOpen }\n open={ open }\n onOpenChange={ onOpenChange }\n isDisabled={ isDisabled }\n { ...props }\n >\n {children}\n </Collapsible>\n </ToolShellCardContext>\n );\n }\n\n return (\n <ToolShellCardContext value={ context }>\n <div\n className={ cn(styles.root, className) }\n data-slot=\"tool-card\"\n { ...props }\n >\n {children}\n </div>\n </ToolShellCardContext>\n );\n}\n\nexport interface ToolShellCardHeaderProps extends Omit<HTMLAttributes<HTMLButtonElement>, 'title' | 'type'> {\n state: string;\n title?: ReactNode;\n /** Optional leading icon before the title (e.g. proxied MCP tools). */\n icon?: ReactNode;\n /** Error or denial detail; shown in a tooltip on the struck title. */\n statusDetail?: string | undefined;\n /** Tool is waiting on the user — do not treat idle non-terminal as stalled. */\n awaitingUser?: boolean;\n}\n\nfunction toolShellCardHeaderLabel(\n title: ReactNode | undefined,\n live: boolean,\n stalled: boolean,\n failed: boolean,\n statusDetail?: string\n): ReactNode {\n if (stalled) {\n if (title != null && typeof title !== 'string' && typeof title !== 'number') {\n return title;\n }\n\n return (\n <Text color=\"secondary\" className=\"truncate\">\n { (typeof title === 'string' || typeof title === 'number')\n ? String(title)\n : TOOL_INTERRUPTED_MESSAGE}\n </Text>\n );\n }\n\n if (title != null && typeof title !== 'string' && typeof title !== 'number') {\n return title;\n }\n\n const canShimmerLabel = typeof title === 'string' || typeof title === 'number';\n\n if (live && canShimmerLabel) {\n return (\n <Shimmer duration={ 1 } className=\"truncate\">\n {String(title)}\n </Shimmer>\n );\n }\n\n if (failed) {\n const label = title == null ? '' : String(title);\n\n return (\n <FailedToolTitleTooltip statusDetail={ statusDetail }>\n <Text\n decoration=\"line-through\"\n color=\"secondary\"\n className=\"truncate\"\n aria-label={ `${ label } failed` }\n >\n {title}\n </Text>\n </FailedToolTitleTooltip>\n );\n }\n\n return (\n <Text className=\"truncate\">{title}</Text>\n );\n}\n\ntype ToolShellCardHeaderViewProps = ToolShellCardHeaderProps & {\n progress: ToolProgressState;\n};\n\nfunction ToolShellCardHeaderStatic({\n state,\n title,\n icon,\n statusDetail,\n className,\n progress,\n children,\n}: ToolShellCardHeaderViewProps) {\n const { live, stalled } = progress;\n const detail = stalled\n ? (statusDetail?.trim() || TOOL_INTERRUPTED_MESSAGE)\n : statusDetail;\n const statusState = stalled ? 'output-error' : state;\n const titleFailed = isFailedToolStatus(statusState, detail);\n\n return (\n <div\n className={ cn(styles.headerNonInteractive, className) }\n aria-busy={ live }\n >\n <div className={ styles.headerMain }>\n <ToolShellStatusIcon\n icon={ icon }\n state={ statusState }\n statusDetail={ detail }\n className={ styles.headerIcon }\n />\n {toolShellCardHeaderLabel(title, live, stalled, titleFailed, detail)}\n </div>\n {children}\n </div>\n );\n}\n\nfunction ToolShellCardHeaderCollapsible({\n state,\n title,\n icon,\n statusDetail,\n className,\n progress,\n children: _children,\n ...props\n}: ToolShellCardHeaderViewProps) {\n const { state: collapsibleState } = useCollapsible();\n const { live, stalled } = progress;\n const detail = stalled\n ? (statusDetail?.trim() || TOOL_INTERRUPTED_MESSAGE)\n : statusDetail;\n const statusState = stalled ? 'output-error' : state;\n const titleFailed = isFailedToolStatus(statusState, detail);\n\n return (\n <CollapsibleTrigger asChild>\n <button\n type=\"button\"\n className={ cn(styles.header, className) }\n aria-busy={ live }\n aria-expanded={ collapsibleState.isExpanded }\n { ...props }\n >\n <div className={ styles.headerMain }>\n <ToolShellStatusIcon\n icon={ icon }\n state={ statusState }\n statusDetail={ detail }\n className={ styles.headerIcon }\n />\n {toolShellCardHeaderLabel(title, live, stalled, titleFailed, detail)}\n </div>\n\n <ChevronDown\n className={ cn('chevron', 'next', styles.toolChevron) }\n aria-expanded={ collapsibleState.isExpanded }\n aria-hidden\n />\n </button>\n </CollapsibleTrigger>\n );\n}\n\nexport function ToolShellCardHeader(props: ToolShellCardHeaderProps) {\n const shell = use(ToolShellCardContext);\n const progress = useToolProgress(props.state, props.awaitingUser);\n\n if (shell?.collapsible) {\n return <ToolShellCardHeaderCollapsible { ...props } progress={ progress } />;\n }\n\n return <ToolShellCardHeaderStatic { ...props } progress={ progress } />;\n}\n\nexport type ToolShellCardContentProps = HTMLAttributes<HTMLDivElement>;\n\nfunction ToolShellCardContentStatic({ className, children, ...props }: ToolShellCardContentProps) {\n return (\n <div className={ cn(styles.content, className) } data-slot=\"tool-card-content\" { ...props }>\n {children}\n </div>\n );\n}\n\nfunction ToolShellCardContentCollapsible({ className, children, ...props }: ToolShellCardContentProps) {\n return (\n <CollapsibleMotionContent>\n <div className={ cn(styles.content, className) } data-slot=\"tool-card-content\" { ...props }>\n {children}\n </div>\n </CollapsibleMotionContent>\n );\n}\n\nexport function ToolShellCardContent({ className, children, ...props }: ToolShellCardContentProps) {\n const shell = use(ToolShellCardContext);\n\n if (shell?.collapsible) {\n return (\n <ToolShellCardContentCollapsible className={ className } { ...props }>\n {children}\n </ToolShellCardContentCollapsible>\n );\n }\n\n return (\n <ToolShellCardContentStatic className={ className } { ...props }>\n {children}\n </ToolShellCardContentStatic>\n );\n}\n\nexport type ToolShellCardFooterProps = HTMLAttributes<HTMLDivElement>;\n\n/** Footer strip for tool errors and approval flows. */\nexport function ToolShellCardFooter({ className, children, ...props }: ToolShellCardFooterProps) {\n return (\n <div className={ cn(styles.footer, className) } data-slot=\"tool-card-footer\" { ...props }>\n {children}\n </div>\n );\n}\n"],"names":["ToolShellCardContext","ToolShellCard","collapsible","defaultOpen","open","onOpenChange","isDisabled","className","children","props","context","useMemo","Collapsible","cn","styles","toolShellCardHeaderLabel","title","live","stalled","failed","statusDetail","Text","TOOL_INTERRUPTED_MESSAGE","Shimmer","label","FailedToolTitleTooltip","ToolShellCardHeaderStatic","state","icon","progress","detail","statusState","titleFailed","isFailedToolStatus","_jsxs","_jsx","ToolShellStatusIcon","ToolShellCardHeaderCollapsible","_children","collapsibleState","useCollapsible","CollapsibleTrigger","ChevronDown","ToolShellCardHeader","shell","use","useToolProgress","ToolShellCardContentStatic","ToolShellCardContentCollapsible","CollapsibleMotionContent","ToolShellCardContent","ToolShellCardFooter"],"mappings":";;;;;;;;;;;AAWA,MAAMA,sBAAkD,IAAI;AAIrD,SAASC,EAAc;AAAA,EAC5B,aAAAC,IAAc;AAAA,EACd,aAAAC,IAAc;AAAA,EACd,MAAAC;AAAA,EACA,cAAAC;AAAA,EACA,YAAAC;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,GAAGC;AACL,GAAG;AACD,QAAMC,IAAUC,EAAQ,OAAO;AAAA,IAC7B,aAAAT;AAAA,EAAA,IACE,CAACA,CAAW,CAAC;AACjB,SAAIA,sBACuBF,GAAsB;AAAA,IAC7C,OAAOU;AAAA,IACP,4BAA4BE,GAAa;AAAA,MACvC,WAAWC,EAAGC,EAAO,MAAMP,CAAS;AAAA,MACpC,aAAa;AAAA,MACb,aAAAJ;AAAA,MACA,MAAAC;AAAA,MACA,cAAAC;AAAA,MACA,YAAAC;AAAA,MACA,GAAGG;AAAA,MACH,UAAAD;AAAA,IAAA,CACD;AAAA,EAAA,CACF,sBAEsBR,GAAsB;AAAA,IAC7C,OAAOU;AAAA,IACP,4BAA4B,OAAO;AAAA,MACjC,WAAWG,EAAGC,EAAO,MAAMP,CAAS;AAAA,MACpC,aAAa;AAAA,MACb,GAAGE;AAAA,MACH,UAAAD;AAAA,IAAA,CACD;AAAA,EAAA,CACF;AACH;AACA,SAASO,EAAyBC,GAAOC,GAAMC,GAASC,GAAQC,GAAc;AAC5E,MAAIF;AACF,WAAIF,KAAS,QAAQ,OAAOA,KAAU,YAAY,OAAOA,KAAU,WAC1DA,sBAEgBK,GAAM;AAAA,MAC7B,OAAO;AAAA,MACP,WAAW;AAAA,MACX,UAAU,OAAOL,KAAU,YAAY,OAAOA,KAAU,WAAW,OAAOA,CAAK,IAAIM;AAAA,IAAA,CACpF;AAEH,MAAIN,KAAS,QAAQ,OAAOA,KAAU,YAAY,OAAOA,KAAU;AACjE,WAAOA;AAGT,MAAIC,MADoB,OAAOD,KAAU,YAAY,OAAOA,KAAU;AAEpE,6BAAyBO,GAAS;AAAA,MAChC,UAAU;AAAA,MACV,WAAW;AAAA,MACX,UAAU,OAAOP,CAAK;AAAA,IAAA,CACvB;AAEH,MAAIG,GAAQ;AACV,UAAMK,IAAQR,KAAS,OAAO,KAAK,OAAOA,CAAK;AAC/C,6BAAyBS,GAAwB;AAAA,MAC/C,cAAAL;AAAA,MACA,4BAA4BC,GAAM;AAAA,QAChC,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,WAAW;AAAA,QACX,cAAc,GAAGG,CAAK;AAAA,QACtB,UAAUR;AAAA,MAAA,CACX;AAAA,IAAA,CACF;AAAA,EACH;AACA,2BAAyBK,GAAM;AAAA,IAC7B,WAAW;AAAA,IACX,UAAUL;AAAA,EAAA,CACX;AACH;AACA,SAASU,EAA0B;AAAA,EACjC,OAAAC;AAAA,EACA,OAAAX;AAAA,EACA,MAAAY;AAAA,EACA,cAAAR;AAAA,EACA,WAAAb;AAAA,EACA,UAAAsB;AAAA,EACA,UAAArB;AACF,GAAG;AACD,QAAM;AAAA,IACJ,MAAAS;AAAA,IACA,SAAAC;AAAA,EAAA,IACEW,GACEC,IAASZ,IAAUE,GAAc,KAAA,KAAUE,IAA2BF,GACtEW,IAAcb,IAAU,iBAAiBS,GACzCK,IAAcC,EAAmBF,GAAaD,CAAM;AAC1D,2BAA0B,OAAO;AAAA,IAC/B,WAAWjB,EAAGC,EAAO,sBAAsBP,CAAS;AAAA,IACpD,aAAaU;AAAA,IACb,UAAU,CAAciB,gBAAAA,EAAM,OAAO;AAAA,MACnC,WAAWpB,EAAO;AAAA,MAClB,UAAU,CAAcqB,gBAAAA,EAAKC,GAAqB;AAAA,QAChD,MAAAR;AAAA,QACA,OAAOG;AAAA,QACP,cAAcD;AAAA,QACd,WAAWhB,EAAO;AAAA,MAAA,CACnB,GAAGC,EAAyBC,GAAOC,GAAMC,GAASc,GAAaF,CAAM,CAAC;AAAA,IAAA,CACxE,GAAGtB,CAAQ;AAAA,EAAA,CACb;AACH;AACA,SAAS6B,EAA+B;AAAA,EACtC,OAAAV;AAAA,EACA,OAAAX;AAAA,EACA,MAAAY;AAAA,EACA,cAAAR;AAAA,EACA,WAAAb;AAAA,EACA,UAAAsB;AAAA,EACA,UAAUS;AAAA,EACV,GAAG7B;AACL,GAAG;AACD,QAAM;AAAA,IACJ,OAAO8B;AAAA,EAAA,IACLC,EAAA,GACE;AAAA,IACJ,MAAAvB;AAAA,IACA,SAAAC;AAAA,EAAA,IACEW,GACEC,IAASZ,IAAUE,GAAc,KAAA,KAAUE,IAA2BF,GACtEW,IAAcb,IAAU,iBAAiBS,GACzCK,IAAcC,EAAmBF,GAAaD,CAAM;AAC1D,2BAAyBW,GAAoB;AAAA,IAC3C,SAAS;AAAA,IACT,4BAA6B,UAAU;AAAA,MACrC,MAAM;AAAA,MACN,WAAW5B,EAAGC,EAAO,QAAQP,CAAS;AAAA,MACtC,aAAaU;AAAA,MACb,iBAAiBsB,EAAiB;AAAA,MAClC,GAAG9B;AAAA,MACH,UAAU,CAAcyB,gBAAAA,EAAM,OAAO;AAAA,QACnC,WAAWpB,EAAO;AAAA,QAClB,UAAU,CAAcqB,gBAAAA,EAAKC,GAAqB;AAAA,UAChD,MAAAR;AAAA,UACA,OAAOG;AAAA,UACP,cAAcD;AAAA,UACd,WAAWhB,EAAO;AAAA,QAAA,CACnB,GAAGC,EAAyBC,GAAOC,GAAMC,GAASc,GAAaF,CAAM,CAAC;AAAA,MAAA,CACxE,GAAgBK,gBAAAA,EAAKO,GAAa;AAAA,QACjC,WAAW7B,EAAG,WAAW,QAAQC,EAAO,WAAW;AAAA,QACnD,iBAAiByB,EAAiB;AAAA,QAClC,eAAe;AAAA,MAAA,CAChB,CAAC;AAAA,IAAA,CACH;AAAA,EAAA,CACF;AACH;AACO,SAASI,EAAoBlC,GAAO;AACzC,QAAMmC,IAAQC,EAAI7C,CAAoB,GAChC6B,IAAWiB,EAAgBrC,EAAM,OAAOA,EAAM,YAAY;AAChE,SAAImC,GAAO,gCACgBP,GAAgC;AAAA,IACvD,GAAG5B;AAAA,IACH,UAAAoB;AAAA,EAAA,CACD,sBAEsBH,GAA2B;AAAA,IAClD,GAAGjB;AAAA,IACH,UAAAoB;AAAA,EAAA,CACD;AACH;AACA,SAASkB,EAA2B;AAAA,EAClC,WAAAxC;AAAA,EACA,UAAAC;AAAA,EACA,GAAGC;AACL,GAAG;AACD,2BAAyB,OAAO;AAAA,IAC9B,WAAWI,EAAGC,EAAO,SAASP,CAAS;AAAA,IACvC,aAAa;AAAA,IACb,GAAGE;AAAA,IACH,UAAAD;AAAA,EAAA,CACD;AACH;AACA,SAASwC,EAAgC;AAAA,EACvC,WAAAzC;AAAA,EACA,UAAAC;AAAA,EACA,GAAGC;AACL,GAAG;AACD,2BAAyBwC,GAA0B;AAAA,IACjD,4BAA4B,OAAO;AAAA,MACjC,WAAWpC,EAAGC,EAAO,SAASP,CAAS;AAAA,MACvC,aAAa;AAAA,MACb,GAAGE;AAAA,MACH,UAAAD;AAAA,IAAA,CACD;AAAA,EAAA,CACF;AACH;AACO,SAAS0C,EAAqB;AAAA,EACnC,WAAA3C;AAAA,EACA,UAAAC;AAAA,EACA,GAAGC;AACL,GAAG;AAED,SADcoC,EAAI7C,CAAoB,GAC3B,gCACgBgD,GAAiC;AAAA,IACxD,WAAAzC;AAAA,IACA,GAAGE;AAAA,IACH,UAAAD;AAAA,EAAA,CACD,sBAEsBuC,GAA4B;AAAA,IACnD,WAAAxC;AAAA,IACA,GAAGE;AAAA,IACH,UAAAD;AAAA,EAAA,CACD;AACH;AAEO,SAAS2C,EAAoB;AAAA,EAClC,WAAA5C;AAAA,EACA,UAAAC;AAAA,EACA,GAAGC;AACL,GAAG;AACD,2BAAyB,OAAO;AAAA,IAC9B,WAAWI,EAAGC,EAAO,QAAQP,CAAS;AAAA,IACtC,aAAa;AAAA,IACb,GAAGE;AAAA,IACH,UAAAD;AAAA,EAAA,CACD;AACH;"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@reforma/components",
3
3
  "description": "A components library for Reforma",
4
4
  "type": "module",
5
- "version": "0.6.0",
5
+ "version": "0.6.2",
6
6
  "license": "UNLICENSED",
7
7
  "author": "Reforma, Inc. <dev@reforma.ai>",
8
8
  "repository": {
@@ -69,9 +69,9 @@
69
69
  "@openuidev/react-lang": "^1.0.1",
70
70
  "@react-aria/dnd": "^3.11.6",
71
71
  "@react-stately/utils": "^3.11.0",
72
- "@reforma/constants": "1.1.0",
72
+ "@reforma/constants": "1.2.0",
73
73
  "@reforma/icons": "0.1.0",
74
- "@reforma/lib": "0.1.7",
74
+ "@reforma/lib": "0.1.8",
75
75
  "@reforma/types": "1.6.0",
76
76
  "@shikijs/transformers": "^4.0.2",
77
77
  "@streamdown/cjk": "1.0.3",