@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.
- package/dist/chat/Message/segments/MessagePhaseSection.module.css +1 -1
- package/dist/chat/Message/turn/MessageAssistantBody.d.ts +2 -1
- package/dist/chat/Message/turn/MessageAssistantBody.d.ts.map +1 -1
- package/dist/chat/Message/turn/MessageAssistantBody.js +62 -58
- package/dist/chat/Message/turn/MessageAssistantBody.js.map +1 -1
- package/dist/chat/Message/turn/workedCollapse.d.ts +6 -2
- package/dist/chat/Message/turn/workedCollapse.d.ts.map +1 -1
- package/dist/chat/Message/turn/workedCollapse.js +24 -18
- package/dist/chat/Message/turn/workedCollapse.js.map +1 -1
- package/dist/chat/Tool/agent/AgentTool.js +5 -5
- package/dist/chat/Tool/agent/AgentTool.js.map +1 -1
- package/dist/chat/Tool/bash/BashTool.js +26 -27
- package/dist/chat/Tool/bash/BashTool.js.map +1 -1
- package/dist/chat/Tool/bash/BashTool.module.css +1 -1
- package/dist/chat/Tool/bash/BashTool.module.css.js +3 -5
- package/dist/chat/Tool/bash/BashTool.module.css.js.map +1 -1
- package/dist/chat/Tool/image-asset/ImageAssetTool.js +1 -1
- package/dist/chat/Tool/image-asset/ImageAssetTool.js.map +1 -1
- package/dist/chat/Tool/shell/ToolShell.js +1 -1
- package/dist/chat/Tool/shell/ToolShell.js.map +1 -1
- package/dist/chat/Tool/shell/ToolShellCard.js +7 -7
- package/dist/chat/Tool/shell/ToolShellCard.js.map +1 -1
- package/package.json +3 -3
|
@@ -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;
|
|
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
|
-
*
|
|
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
|
|
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
|
|
2
|
-
import { cn as
|
|
3
|
-
import { observer as
|
|
4
|
-
import { Button as
|
|
5
|
-
import { Collapsible as
|
|
6
|
-
import { For as
|
|
7
|
-
import { Show as
|
|
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
|
|
10
|
-
import { MessagePhaseSection as
|
|
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
|
|
13
|
-
import { splitFinishedWork as
|
|
14
|
-
import { jsx as r, jsxs as
|
|
15
|
-
function
|
|
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
|
|
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:
|
|
32
|
+
phaseActiveIndex: h,
|
|
33
33
|
getPhaseStats: o,
|
|
34
|
-
lastPart:
|
|
34
|
+
lastPart: d,
|
|
35
35
|
loaderParts: f,
|
|
36
36
|
markTail: a
|
|
37
37
|
}) {
|
|
38
|
-
return /* @__PURE__ */ r(
|
|
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(
|
|
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 ===
|
|
51
|
-
fileStats: i.layout === "grouped" ? o?.(
|
|
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:
|
|
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
|
|
61
|
+
function O({
|
|
62
62
|
label: t
|
|
63
63
|
}) {
|
|
64
64
|
const {
|
|
65
65
|
state: e
|
|
66
66
|
} = P();
|
|
67
|
-
return /* @__PURE__ */ r(
|
|
67
|
+
return /* @__PURE__ */ r(M, {
|
|
68
68
|
asChild: !0,
|
|
69
|
-
children: /* @__PURE__ */
|
|
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(
|
|
75
|
-
className:
|
|
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
|
|
82
|
+
function R({
|
|
83
83
|
children: t
|
|
84
84
|
}) {
|
|
85
85
|
const {
|
|
86
86
|
state: e
|
|
87
87
|
} = P();
|
|
88
|
-
return /* @__PURE__ */ r(
|
|
88
|
+
return /* @__PURE__ */ r(u, {
|
|
89
89
|
when: e.isExpanded,
|
|
90
|
-
children: /* @__PURE__ */ r(
|
|
90
|
+
children: /* @__PURE__ */ r(W, {
|
|
91
91
|
className: v.workedPanel,
|
|
92
92
|
children: t
|
|
93
93
|
})
|
|
94
94
|
});
|
|
95
95
|
}
|
|
96
|
-
function
|
|
96
|
+
function q({
|
|
97
97
|
label: t,
|
|
98
98
|
children: e
|
|
99
99
|
}) {
|
|
100
|
-
return /* @__PURE__ */
|
|
100
|
+
return /* @__PURE__ */ p(L, {
|
|
101
101
|
className: v.worked,
|
|
102
102
|
defaultOpen: !1,
|
|
103
|
-
children: [/* @__PURE__ */ r(
|
|
103
|
+
children: [/* @__PURE__ */ r(O, {
|
|
104
104
|
label: t
|
|
105
|
-
}), /* @__PURE__ */ r(
|
|
105
|
+
}), /* @__PURE__ */ r(R, {
|
|
106
106
|
children: e
|
|
107
107
|
})]
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
|
-
const
|
|
110
|
+
const se = F(({
|
|
111
111
|
hideSources: t = !1
|
|
112
112
|
} = {}) => {
|
|
113
|
-
const 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:
|
|
120
|
+
turnActive: h,
|
|
121
121
|
isStreaming: o,
|
|
122
|
-
isLastMessage:
|
|
122
|
+
isLastMessage: d,
|
|
123
123
|
getPhaseStats: f
|
|
124
|
-
} = e, a = t ?
|
|
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 =
|
|
127
|
+
const g = j(a, o), m = D(a, {
|
|
128
128
|
streaming: o,
|
|
129
|
-
cancelled: c?.stopReason === "cancelled"
|
|
130
|
-
|
|
129
|
+
cancelled: c?.stopReason === "cancelled",
|
|
130
|
+
superseded: !d
|
|
131
|
+
}), k = {
|
|
131
132
|
messageId: s,
|
|
132
133
|
isStreaming: o,
|
|
133
|
-
isLiveMessage:
|
|
134
|
-
turnActive:
|
|
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(
|
|
141
|
+
return /* @__PURE__ */ r(u, {
|
|
141
142
|
when: m,
|
|
142
|
-
fallback: /* @__PURE__ */
|
|
143
|
-
children: [/* @__PURE__ */ r(
|
|
144
|
-
...
|
|
143
|
+
fallback: /* @__PURE__ */ p(b, {
|
|
144
|
+
children: [/* @__PURE__ */ r(w, {
|
|
145
|
+
...k,
|
|
145
146
|
segments: a,
|
|
146
147
|
markTail: !0
|
|
147
|
-
}), /* @__PURE__ */ r(
|
|
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__ */
|
|
157
|
-
children: [/* @__PURE__ */ r(
|
|
158
|
-
label:
|
|
159
|
-
children: /* @__PURE__ */ r(
|
|
160
|
-
...
|
|
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(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
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;
|
|
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
|
|
4
|
-
if (
|
|
5
|
-
return
|
|
6
|
-
const
|
|
7
|
-
|
|
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
|
|
10
|
-
return
|
|
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
|
|
16
|
-
if (r == null ||
|
|
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((
|
|
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
|
|
22
|
-
if (
|
|
23
|
-
return
|
|
24
|
-
const
|
|
25
|
-
return
|
|
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
|
-
|
|
29
|
-
|
|
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
|
|
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 ? "
|
|
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,
|
|
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
|
-
}),
|
|
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?.(
|
|
233
|
+
onOpen: k ? () => n?.(b, A) : void 0,
|
|
234
234
|
running: c && !f && !l,
|
|
235
235
|
stalled: l,
|
|
236
|
-
title: c && !f && !l ?
|
|
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
|
|
2
|
-
import { isStaticToolUIPart as
|
|
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
|
|
6
|
-
import { Text as
|
|
7
|
-
import { Approval as
|
|
8
|
-
import { getToolFailureRowState as
|
|
9
|
-
import { ToolShell as
|
|
10
|
-
import
|
|
11
|
-
import { jsxs as
|
|
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
|
|
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 === "" ?
|
|
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 =
|
|
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 =
|
|
94
|
-
return /* @__PURE__ */
|
|
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(
|
|
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(
|
|
102
|
+
icon: p ? /* @__PURE__ */ s(x, {
|
|
103
103
|
"aria-hidden": !0
|
|
104
|
-
}) :
|
|
104
|
+
}) : v ? /* @__PURE__ */ s(b, {
|
|
105
105
|
"aria-hidden": !0
|
|
106
|
-
}) : /* @__PURE__ */ s(
|
|
106
|
+
}) : /* @__PURE__ */ s(k, {
|
|
107
107
|
"aria-hidden": !0
|
|
108
108
|
})
|
|
109
109
|
}), /* @__PURE__ */ s(h, {
|
|
110
110
|
when: f,
|
|
111
|
-
children: /* @__PURE__ */ s(
|
|
112
|
-
|
|
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:
|
|
116
|
+
className: q.terminalPanel
|
|
118
117
|
})
|
|
119
118
|
})
|
|
120
119
|
}), /* @__PURE__ */ s(h, {
|
|
121
120
|
when: i === "approval-requested",
|
|
122
|
-
children: /* @__PURE__ */ s(
|
|
123
|
-
children: /* @__PURE__ */ s(
|
|
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__ */
|
|
128
|
-
children: [/* @__PURE__ */ s(
|
|
126
|
+
children: /* @__PURE__ */ g(R, {
|
|
127
|
+
children: [/* @__PURE__ */ s(S, {
|
|
129
128
|
children: "Confirm you want to run this command"
|
|
130
|
-
}), /* @__PURE__ */ s(
|
|
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
|
-
.
|
|
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
|
|
2
|
-
|
|
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
|
-
|
|
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":";;;"}
|
|
@@ -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":";;;;;;;;;;;;;;;;;;;AAmBA,MAAMA,IAAmB,oBAAI,IAAI,CAAC,YAAY,eAAe,aAAa,CAAC;AAC3E,SAASC,EAAYC,GAAQ;AAC3B,MAAI,SAAOA,KAAW,YAAYA,MAAW,QAAQ,EAAE,QAAQA;AAG/D,WAAOA;AACT;AAGA,SAASC,EAAWC,GAAOC,GAAM;AAC/B,QAAMC,IAAWF,EAAM,KAAK,UAAUA,EAAM,YAAY,KAAA;AACxD,MAAIE;AACF,WAAOA;AAET,QAAMC,IAAaH,EAAM,YAAY,KAAA;AACrC,MAAI,GAACG,KAAc,CAACF;AAGpB,QAAI;AACF,aAAO,IAAI,IAAIE,GAAYF,CAAI,EAAE;AAAA,IACnC,QAAQ;AACN;AAAA,IACF;AACF;AACA,SAASG,EAAUC,GAAUC,GAAO;AAClC,SAAID,MAAa,gBACXC,IAAQ,IACH;AAAA,IACL,UAAU,WAAWA,CAAK;AAAA,IAC1B,MAAM,SAASA,CAAK;AAAA,EAAA,IAGjB;AAAA,IACL,UAAU;AAAA,IACV,MAAM;AAAA,EAAA,IAGND,MAAa,gBACR;AAAA,IACL,UAAU;AAAA,IACV,MAAM;AAAA,EAAA,IAGNC,IAAQ,IACH;AAAA,IACL,UAAU,cAAcA,CAAK;AAAA,IAC7B,MAAM,aAAaA,CAAK;AAAA,EAAA,IAGrB;AAAA,IACL,UAAU;AAAA,IACV,MAAM;AAAA,EAAA;AAEV;AACA,SAASC,EAAaF,GAAU;AAC9B,SAAIA,MAAa,gBACR,yBAELA,MAAa,gBACR,yBAEF;AACT;AACA,SAASG,EAAc;AAAA,EACrB,QAAAC;AACF,GAAG;AACD,QAAMC,IAAcD,EAAO,WAAW,KAAA,GAChCE,IAAeF,EAAO,YAAY,KAAA,KAAU;AAClD,2BAA0BG,GAAM;AAAA,IAC9B,SAAS;AAAA,IACT,WAAWC,EAAO;AAAA,IAClB,UAAU,CAAC,YAAY,uBAAuBC,GAAM;AAAA,MAClD,MAAMJ;AAAA,MACN,4BAA4B,QAAQ;AAAA,QAClC,UAAUD,EAAO;AAAA,MAAA,CAClB;AAAA,MACD,UAAU,CAAAM,MAAqBC,gBAAAA,EAAK,KAAK;AAAA,QACvC,WAAWH,EAAO;AAAA,QAClB,MAAAE;AAAA,QACA,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,UAAUN,EAAO;AAAA,MAAA,CAClB;AAAA,IAAA,CACF,GAAG,OAAoBO,gBAAAA,EAAK,KAAK;AAAA,MAChC,WAAWH,EAAO;AAAA,MAClB,MAAMF;AAAA,MACN,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,UAAU;AAAA,IAAA,CACX,CAAC;AAAA,EAAA,CACH;AACH;AACA,SAASM,EAAYC,GAAQ;AAC3B,QAAMC,wBAAW,IAAA,GACXC,IAAQ,CAAA;AACd,aAAWC,KAASH,GAAQ;AAC1B,UAAMI,IAAOD,GAAO,KAAA;AACpB,IAAI,CAACC,KAAQH,EAAK,IAAIG,CAAI,MAG1BH,EAAK,IAAIG,CAAI,GACbF,EAAM,KAAKE,CAAI;AAAA,EACjB;AACA,SAAOF;AACT;AAGA,SAASG,EAAaC,GAAM;AAC1B,QAAMC,IAAaR,EAAYO,EAAK,OAAO,IAAI,CAAAxB,MAASA,EAAM,GAAG,CAAC;AAClE,MAAIyB,EAAW,SAAS;AACtB,WAAOA;AAET,QAAMC,IAAcT,GAAaO,EAAK,WAAW,IAAI,IAAI,CAAAG,MAAQA,EAAK,GAAG,CAAC;AAC1E,SAAID,EAAY,SAAS,IAChBA,IAELF,EAAK,SAAS,SAAS,KAAK,IACvBP,EAAYO,EAAK,SAAS,MAAM,KAAK,CAAC,IAExCA,EAAK,WAAW,CAACA,EAAK,QAAQ,IAAI,CAAA;AAC3C;AACA,SAASI,GAAeC,GAAO;AAC7B,QAAMC,IAAUD,GAAO,SAAS,UAAU,GACpCvB,IAAQ,OAAOuB,GAAO,SAAU,YAAYA,EAAM,QAAQ,IAAIA,EAAM,QAAQ;AAClF,SAAO,KAAK,IAAIC,GAASxB,GAAO,CAAC;AACnC;AACA,SAASyB,GAAcC,GAAQ;AAC7B,QAAMb,wBAAW,IAAA,GACXc,IAAU,CAAA;AAChB,aAAWjC,KAASgC,GAAQ;AAC1B,QAAI,CAAChC,EAAM;AACT;AAEF,UAAMkC,IAAMlC,EAAM,OAAO,cAAcA,EAAM,OAAO;AACpD,IAAImB,EAAK,IAAIe,CAAG,MAGhBf,EAAK,IAAIe,CAAG,GACZD,EAAQ,KAAKjC,EAAM,MAAM;AAAA,EAC3B;AACA,SAAOiC;AACT;AACA,SAASE,GAAQ;AAAA,EACf,MAAAC;AACF,GAAG;AACD,MAAI,CAACA,EAAK;AACR,WAAO;AAET,QAAMC,IAAMD,EAAK;AACjB,2BAAyBE,GAAU;AAAA,IACjC,KAAKF,EAAK;AAAA,IACV,KAAAC;AAAA,IACA,UAAU,CAAAE,MAAqBvB,gBAAAA,EAAKwB,GAAW;AAAA,MAC7C,cAAc,QAAQJ,EAAK,GAAG;AAAA,MAC9B,WAAWvB,EAAO;AAAA,MAClB,SAAS0B;AAAA,MACT,4BAA4BE,GAAO;AAAA,QACjC,KAAK;AAAA,QACL,WAAW5B,EAAO;AAAA,QAClB,KAAAwB;AAAA,MAAA,CACD;AAAA,IAAA,CACF;AAAA,EAAA,CACF;AACH;AACO,SAASK,GAAmB;AAAA,EACjC,OAAAC;AAAA,EACA,OAAAC;AACF,GAAG;AACD,2BAAyB,OAAO;AAAA,IAC9B,WAAW/B,EAAO;AAAA,IAClB,cAAc+B,EAAM;AAAA,IACpB,OAAO;AAAA,MACL,OAAOA,EAAM;AAAA,IAAA;AAAA,IAEf,4BAA4BC,GAAK;AAAA,MAC/B,MAAMD;AAAA,MACN,UAAU,CAACR,GAAMU,GAAO;AAAA,QACtB,QAAAC;AAAA,MAAA,wBACuB,OAAO;AAAA,QAC9B,WAAWlC,EAAO;AAAA,QAClB,OAAO;AAAA,UACL,OAAOiC;AAAA,QAAA;AAAA,QAET,UAAU,CAAc9B,gBAAAA,EAAKmB,IAAS;AAAA,UACpC,MAAAC;AAAA,QAAA,CACD,GAAgBpB,gBAAAA,EAAKF,GAAM;AAAA,UAC1B,MAAMiC,KAAUJ,MAAU;AAAA,UAC1B,4BAA4BK,GAAgB;AAAA,YAC1C,eAAe;AAAA,YACf,WAAWnC,EAAO;AAAA,YAClB,MAAM;AAAA,UAAA,CACP;AAAA,QAAA,CACF,GAAgBG,gBAAAA,EAAKF,GAAM;AAAA,UAC1B,MAAMiC,KAAUJ,MAAU;AAAA,UAC1B,4BAA4BM,GAAmB;AAAA,YAC7C,eAAe;AAAA,YACf,WAAWpC,EAAO;AAAA,YAClB,MAAM;AAAA,UAAA,CACP;AAAA,QAAA,CACF,CAAC;AAAA,MAAA,GACDuB,EAAK,GAAG;AAAA,IAAA,CACZ;AAAA,EAAA,CACF;AACH;AACO,SAASc,GAAoB;AAAA,EAClC,QAAAC;AAAA,EACA,MAAAC;AAAA,EACA,MAAAC;AAAA,EACA,UAAAC;AAAA,EACA,SAAAC;AAAA,EACA,cAAAC;AACF,GAAG;AACD,SAAID,sBACuB3C,GAAM;AAAA,IAC7B,WAAWC,EAAO;AAAA,IAClB,OAAO;AAAA,IACP,UAAU4C;AAAA,EAAA,CACX,IAECJ,sBACuBK,GAAS;AAAA,IAChC,IAAI;AAAA,IACJ,WAAW7C,EAAO;AAAA,IAClB,UAAU;AAAA,IACV,UAAUyC;AAAA,EAAA,CACX,IAECH,sBACuBQ,GAAwB;AAAA,IAC/C,cAAAH;AAAA,IACA,4BAA4B5C,GAAM;AAAA,MAChC,WAAWC,EAAO;AAAA,MAClB,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,UAAUuC;AAAA,IAAA,CACX;AAAA,EAAA,CACF,sBAEsBxC,GAAM;AAAA,IAC7B,WAAWC,EAAO;AAAA,IAClB,UAAUuC;AAAA,EAAA,CACX;AACH;AAGO,SAASQ,GAAe;AAAA,EAC7B,MAAAC;AACF,GAAG;AACD,QAAMxD,IAAWyD,EAAYD,CAAI,GAC3B;AAAA,IACJ,YAAAE;AAAA,EAAA,IACEC,EAAA,GACE;AAAA,IACJ,MAAAX;AAAA,IACA,SAAAE;AAAA,EAAA,IACEU,EAAgBJ,EAAK,KAAK;AAC9B,MAAI,CAACjE,EAAiB,IAAIS,CAAQ;AAChC,WAAO;AAET,QAAM6D,IAAQL,EAAK,OACbM,IAAUC,EAAuBP,CAAI,GAErC/D,IADOoE,MAAU,qBACDrE,EAAYgE,EAAK,MAAM,IAAI,QAC3CQ,IAAUvE,GAAQ,OAAO,KAAOA,IAAS,QACzCwE,IAAQxE,GAAQ,OAAO,KAAQA,EAAO,QAAQqE,EAAQ,SACtDnC,IAASqC,GAAS,UAAU,CAAA,GAC5BxC,IAAQ,OAAOgC,EAAK,SAAU,YAAYA,EAAK,UAAU,OAAOA,EAAK,QAAQ,QAC7EU,IAAYzE,KAAU,SAASA,KAAU,OAAOA,EAAO,OAAQ,WAAWA,EAAO,MAAM,QACvF0E,IAAc1E,KAAU,WAAWA,KAAU,OAAOA,EAAO,SAAU,WAAWA,EAAO,QAAQ,QAE/F2E,KAAYJ,GAAS,OAAOE,KAAa1C,GAAO,OAAOwC,GAAS,SAASG,KAAe3C,GAAO,SAAS,IAAI,KAAA,GAE5G6C,IAAc,CADDC,EAA2BT,CAAK,KAChBlC,EAAO,WAAW,GAC/C4C,IAAQ5C,EAAO,SAAS,IAAIA,EAAO,SAASJ,GAAeC,CAAK,GAChEgD,IAASzE,EAAUC,GAAUuE,CAAK,GAClCxD,IAAQH,EAAY,CAAC,GAAGM,EAAa;AAAA,IACzC,QAAAS;AAAA,IACA,SAASH,GAAO;AAAA,IAChB,UAAA4C;AAAA,EAAA,CACD,GAAG,GAAGzC,EAAO,QAAQ,OAASjC,EAAWC,GAAO+D,CAAU,IAAI,CAAA,IAAK,CAAC/D,EAAM,IAAI,CAAC,CAAC,CAAC,GAC5EiC,IAAUF,GAAcC,CAAM,GAC9BY,IAAQ8B,IAAc,CAAC;AAAA,IAC3B,KAAK;AAAA,IACL,KAAKnE,EAAaF,CAAQ;AAAA,EAAA,CAC3B,IAAI2B,EAAO,SAAS,IAAIA,EAAO,IAAI,CAAChC,GAAO8C,MAAU;AACpD,UAAMT,IAAMtC,EAAWC,GAAO+D,CAAU;AACxC,WAAO;AAAA,MACL,KAAK1B,KAAOrC,EAAM,QAAQ,SAAS8C,CAAK;AAAA,MACxC,KAAAT;AAAA,MACA,KAAKrC,EAAM,KAAK,UAAUoB,EAAM0B,CAAK,KAAK,SAASA,IAAQ,CAAC;AAAA,IAAA;AAAA,EAEhE,CAAC,IAAI,MAAM,KAAK;AAAA,IACd,QAAQ8B;AAAA,EAAA,GACP,CAACE,GAAGhC,OAAW;AAAA,IAChB,KAAK,eAAeA,CAAK;AAAA,IACzB,KAAK1B,EAAM0B,CAAK,KAAK+B,EAAO;AAAA,EAAA,EAC5B;AACF,2BAAyBE,GAAe;AAAA,IACtC,aAAa1B;AAAA,IACb,WAAW2B,EAAY;AAAA,IACvB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,4BAA6BC,GAAK;AAAA,MAChC,WAAW;AAAA,MACX,WAAW;AAAA,MACX,KAAK;AAAA,MACL,SAAS;AAAA,MACT,UAAU,CAAcjE,gBAAAA,EAAK0B,IAAoB;AAAA,QAC/C,OAAOW,IAAO,WAAWqB,IAAc,UAAU;AAAA,QACjD,OAAA9B;AAAA,MAAA,CACD,GAAgBsC,gBAAAA,EAAMD,GAAK;AAAA,QAC1B,KAAK;AAAA,QACL,MAAM;AAAA,QACN,UAAU,CAAcjE,gBAAAA,EAAKkC,IAAqB;AAAA,UAChD,QAAQ,CAACwB,KAAe,EAAQJ;AAAA,UAChC,MAAMI,IAAcnE,EAAaF,CAAQ,IAAIwE,EAAO;AAAA,UACpD,MAAAxB;AAAA,UACA,UAAUwB,EAAO;AAAA,UACjB,SAAAtB;AAAA,UACA,cAAce;AAAA,QAAA,CACf,GAAgBtD,gBAAAA,EAAKF,GAAM;AAAA,UAC1B,MAAMM,EAAM,WAAW;AAAA,UACvB,4BAA4BR,GAAM;AAAA,YAChC,WAAWC,EAAO;AAAA,YAClB,OAAO;AAAA,YACP,SAAS;AAAA,YACT,UAAUO,EAAM,CAAC;AAAA,UAAA,CAClB;AAAA,QAAA,CACF,GAAgBJ,gBAAAA,EAAKF,GAAM;AAAA,UAC1B,MAAMM,EAAM,SAAS;AAAA,UACrB,4BAA4B,MAAM;AAAA,YAChC,WAAWP,EAAO;AAAA,YAClB,4BAA4BgC,GAAK;AAAA,cAC/B,MAAMzB;AAAA,cACN,UAAU,CAAAE,MAAqBN,gBAAAA,EAAK,MAAM;AAAA,gBACxC,4BAA4BJ,GAAM;AAAA,kBAChC,WAAWC,EAAO;AAAA,kBAClB,OAAO;AAAA,kBACP,SAAS;AAAA,kBACT,UAAUS;AAAA,gBAAA,CACX;AAAA,cAAA,GACAA,CAAI;AAAA,YAAA,CACR;AAAA,UAAA,CACF;AAAA,QAAA,CACF,GAAgBN,gBAAAA,EAAKF,GAAM;AAAA,UAC1B,MAAMmB,EAAQ,SAAS;AAAA,UACvB,4BAA4B,OAAO;AAAA,YACjC,WAAWpB,EAAO;AAAA,YAClB,4BAA4BgC,GAAK;AAAA,cAC/B,MAAMZ;AAAA,cACN,UAAU,CAAAxB,MAAuBO,gBAAAA,EAAKR,GAAe;AAAA,gBACnD,QAAAC;AAAA,cAAA,GACCA,EAAO,cAAcA,EAAO,IAAI;AAAA,YAAA,CACpC;AAAA,UAAA,CACF;AAAA,QAAA,CACF,CAAC;AAAA,MAAA,CACH,CAAC;AAAA,IAAA,CACH;AAAA,EAAA,CACF;AACH;"}
|
|
@@ -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
|
|
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
|
|
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: "
|
|
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(
|
|
99
|
+
children: [/* @__PURE__ */ o(y, {
|
|
100
100
|
icon: r,
|
|
101
101
|
state: h,
|
|
102
102
|
statusDetail: m,
|
|
103
103
|
className: a.headerIcon
|
|
104
|
-
}),
|
|
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(
|
|
134
|
+
children: [/* @__PURE__ */ o(y, {
|
|
135
135
|
icon: r,
|
|
136
136
|
state: T,
|
|
137
137
|
statusDetail: f,
|
|
138
138
|
className: a.headerIcon
|
|
139
|
-
}),
|
|
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":"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"}
|
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.
|
|
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.
|
|
72
|
+
"@reforma/constants": "1.2.0",
|
|
73
73
|
"@reforma/icons": "0.1.0",
|
|
74
|
-
"@reforma/lib": "0.1.
|
|
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",
|