@reforma/components 0.1.3 → 0.1.5
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/ToggleButtonGroup/ToggleButtonGroup.module.css +1 -1
- package/dist/chat/ComposerBanner/ComposerBanner.d.ts.map +1 -1
- package/dist/chat/ComposerBanner/ComposerBanner.js +16 -15
- package/dist/chat/ComposerBanner/ComposerBanner.js.map +1 -1
- package/dist/chat/Message/turn/Message.module.css +1 -1
- package/dist/chat/Message/turn/Message.module.css.js +22 -16
- package/dist/chat/Message/turn/Message.module.css.js.map +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 +148 -56
- package/dist/chat/Message/turn/MessageAssistantBody.js.map +1 -1
- package/dist/chat/Message/turn/MessageUserBubble.d.ts.map +1 -1
- package/dist/chat/Message/turn/MessageUserBubble.js +52 -53
- package/dist/chat/Message/turn/MessageUserBubble.js.map +1 -1
- package/dist/chat/Message/turn/workedCollapse.d.ts +16 -0
- package/dist/chat/Message/turn/workedCollapse.d.ts.map +1 -0
- package/dist/chat/Message/turn/workedCollapse.js +31 -0
- package/dist/chat/Message/turn/workedCollapse.js.map +1 -0
- package/dist/chat/Tool/agent/AgentTool.d.ts +10 -0
- package/dist/chat/Tool/agent/AgentTool.d.ts.map +1 -1
- package/dist/chat/Tool/agent/AgentTool.js +110 -99
- package/dist/chat/Tool/agent/AgentTool.js.map +1 -1
- package/dist/chat/Tool/index.d.ts +1 -1
- package/dist/chat/Tool/index.d.ts.map +1 -1
- package/dist/chat/Tool/index.js +45 -44
- package/dist/chat/index.js +62 -61
- package/dist/index.js +364 -363
- package/package.json +1 -1
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { cn as
|
|
2
|
-
import { resolveLayerCite as
|
|
3
|
-
import { observer as
|
|
4
|
-
import { useState as
|
|
5
|
-
import { For as
|
|
6
|
-
import { Scrollable as
|
|
7
|
-
import { ScrollExpandChevronButton as
|
|
1
|
+
import { cn as x } from "@reforma/lib";
|
|
2
|
+
import { resolveLayerCite as g, attachedLayerRefKey as S, formatLayerCite as v, codeEditorStateKey as M } from "@reforma/types";
|
|
3
|
+
import { observer as N } from "mobx-react-lite";
|
|
4
|
+
import { useState as E } from "react";
|
|
5
|
+
import { For as $ } from "../../../For/For.js";
|
|
6
|
+
import { Scrollable as w } from "../../../Scrollable/Scrollable.js";
|
|
7
|
+
import { ScrollExpandChevronButton as B } from "../../../Scrollable/ScrollExpandChevronButton.js";
|
|
8
8
|
import { Show as f } from "../../../Show/Show.js";
|
|
9
|
-
import { Badge as
|
|
10
|
-
import { useChat as
|
|
11
|
-
import { Chip as
|
|
12
|
-
import { chipItemFromPath as
|
|
13
|
-
import { fileCite as
|
|
9
|
+
import { Badge as L } from "../../../Tag/Badge.js";
|
|
10
|
+
import { useChat as k } from "../../ChatContext.js";
|
|
11
|
+
import { Chip as A } from "../../Chip/Chip.js";
|
|
12
|
+
import { chipItemFromPath as U } from "../../Chip/helpers/chipPath.js";
|
|
13
|
+
import { fileCite as _, fileChipDisplay as I } from "../../Chip/helpers/cursorLines.js";
|
|
14
14
|
import { MessageText as y } from "../streamdown/MessageText.js";
|
|
15
15
|
import i from "./Message.module.css.js";
|
|
16
|
-
import { useMessageTurn as
|
|
17
|
-
import { jsx as l, jsxs as
|
|
18
|
-
const R = 500,
|
|
16
|
+
import { useMessageTurn as P } from "./messageTurnContext.js";
|
|
17
|
+
import { jsx as l, jsxs as C } from "react/jsx-runtime";
|
|
18
|
+
const R = 500, b = {
|
|
19
19
|
expand: "Show full message",
|
|
20
20
|
collapse: "Show less"
|
|
21
21
|
};
|
|
22
22
|
function F(s) {
|
|
23
|
-
const a =
|
|
23
|
+
const a = U(s.path);
|
|
24
24
|
return {
|
|
25
|
-
id:
|
|
25
|
+
id: M(s),
|
|
26
26
|
path: a?.path ?? s.path,
|
|
27
|
-
label:
|
|
27
|
+
label: I(s),
|
|
28
28
|
tooltip: a?.tooltip,
|
|
29
29
|
...a?.icon ? {
|
|
30
30
|
icon: a.icon
|
|
@@ -35,8 +35,8 @@ function F(s) {
|
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
37
|
function T(s, a) {
|
|
38
|
-
const
|
|
39
|
-
const r =
|
|
38
|
+
const n = a?.attached?.files ?? [], p = a?.attached?.layers ?? [], m = [.../* @__PURE__ */ new Set([...a?.skills ?? [], ...a?.commands ?? []])], e = [...n.map((t) => {
|
|
39
|
+
const r = _(t);
|
|
40
40
|
return {
|
|
41
41
|
cite: r,
|
|
42
42
|
segment: {
|
|
@@ -45,8 +45,8 @@ function T(s, a) {
|
|
|
45
45
|
file: t
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
-
}), ...
|
|
49
|
-
const r =
|
|
48
|
+
}), ...p.map((t) => {
|
|
49
|
+
const r = v(t);
|
|
50
50
|
return {
|
|
51
51
|
cite: r,
|
|
52
52
|
segment: {
|
|
@@ -113,7 +113,7 @@ function d({
|
|
|
113
113
|
item: s,
|
|
114
114
|
onOpenPath: a
|
|
115
115
|
}) {
|
|
116
|
-
return /* @__PURE__ */ l(
|
|
116
|
+
return /* @__PURE__ */ l(A, {
|
|
117
117
|
className: i.userCite,
|
|
118
118
|
item: s,
|
|
119
119
|
onAction: s.href ? void 0 : a
|
|
@@ -122,22 +122,22 @@ function d({
|
|
|
122
122
|
function j({
|
|
123
123
|
text: s,
|
|
124
124
|
metadata: a,
|
|
125
|
-
onOpenPath:
|
|
125
|
+
onOpenPath: n
|
|
126
126
|
}) {
|
|
127
|
-
const
|
|
128
|
-
return
|
|
127
|
+
const p = T(s, a);
|
|
128
|
+
return p.length === 0 ? null : !p.some((e) => e.type !== "text") && p[0]?.type === "text" ? /* @__PURE__ */ l(y, {
|
|
129
129
|
className: i.userMessageBody,
|
|
130
130
|
mode: "static",
|
|
131
|
-
children:
|
|
131
|
+
children: p[0].value
|
|
132
132
|
}) : /* @__PURE__ */ l("div", {
|
|
133
|
-
className:
|
|
134
|
-
children: /* @__PURE__ */ l(
|
|
135
|
-
each:
|
|
133
|
+
className: x(i.userMessageBody, i.userMessageWithCites),
|
|
134
|
+
children: /* @__PURE__ */ l($, {
|
|
135
|
+
each: p,
|
|
136
136
|
children: (e, c) => e.type === "text" ? /* @__PURE__ */ l(y, {
|
|
137
137
|
className: i.userMessageFragment,
|
|
138
138
|
mode: "static",
|
|
139
139
|
children: e.value
|
|
140
|
-
}, `t-${c}`) : e.type === "command" ? /* @__PURE__ */ l(
|
|
140
|
+
}, `t-${c}`) : e.type === "command" ? /* @__PURE__ */ l(L, {
|
|
141
141
|
size: "xs",
|
|
142
142
|
color: "success",
|
|
143
143
|
value: e.skill,
|
|
@@ -147,7 +147,7 @@ function j({
|
|
|
147
147
|
children: e.cite
|
|
148
148
|
}, `c-${e.cite}-${c}`) : e.type === "file" ? /* @__PURE__ */ l(d, {
|
|
149
149
|
item: F(e.file),
|
|
150
|
-
onOpenPath:
|
|
150
|
+
onOpenPath: n
|
|
151
151
|
}, `f-${e.cite}-${c}`) : e.type === "link" ? /* @__PURE__ */ l(d, {
|
|
152
152
|
item: {
|
|
153
153
|
id: e.url,
|
|
@@ -156,25 +156,25 @@ function j({
|
|
|
156
156
|
tooltip: e.url,
|
|
157
157
|
href: e.url
|
|
158
158
|
},
|
|
159
|
-
onOpenPath:
|
|
159
|
+
onOpenPath: n
|
|
160
160
|
}, `u-${e.cite}-${c}`) : /* @__PURE__ */ l(d, {
|
|
161
161
|
item: {
|
|
162
|
-
id:
|
|
162
|
+
id: S(e.layer),
|
|
163
163
|
type: "element",
|
|
164
|
-
label: e.layer.propName ? `${
|
|
164
|
+
label: e.layer.propName ? `${g(e.layer)}.${e.layer.propName}` : e.layer.text || e.layer.label || e.layer.layerId,
|
|
165
165
|
...e.layer.icon ? {
|
|
166
166
|
icon: e.layer.icon
|
|
167
167
|
} : {}
|
|
168
168
|
},
|
|
169
|
-
onOpenPath:
|
|
169
|
+
onOpenPath: n
|
|
170
170
|
}, `l-${e.cite}-${c}`)
|
|
171
171
|
})
|
|
172
172
|
});
|
|
173
173
|
}
|
|
174
|
-
const se =
|
|
175
|
-
const s =
|
|
174
|
+
const se = N(() => {
|
|
175
|
+
const s = P(), {
|
|
176
176
|
onOpenPath: a
|
|
177
|
-
} =
|
|
177
|
+
} = k(), [n, p] = E(!1);
|
|
178
178
|
if (s?.role !== "user" || s.message.role !== "user")
|
|
179
179
|
return null;
|
|
180
180
|
const {
|
|
@@ -188,32 +188,31 @@ const se = M(() => {
|
|
|
188
188
|
metadata: e.metadata,
|
|
189
189
|
onOpenPath: a
|
|
190
190
|
}), r = m.length > R;
|
|
191
|
-
return /* @__PURE__ */
|
|
192
|
-
className:
|
|
191
|
+
return /* @__PURE__ */ C("div", {
|
|
192
|
+
className: x(i.messageBubble, i.userBubble),
|
|
193
193
|
children: [/* @__PURE__ */ l(f, {
|
|
194
194
|
when: !r,
|
|
195
195
|
children: /* @__PURE__ */ l("div", {
|
|
196
196
|
className: i.parts,
|
|
197
197
|
children: t
|
|
198
198
|
})
|
|
199
|
-
}), /* @__PURE__ */
|
|
199
|
+
}), /* @__PURE__ */ C(f, {
|
|
200
200
|
when: r,
|
|
201
|
-
children: /* @__PURE__ */ l(
|
|
201
|
+
children: [/* @__PURE__ */ l(w, {
|
|
202
202
|
vertical: !0,
|
|
203
|
-
edgeFade: !
|
|
203
|
+
edgeFade: !n,
|
|
204
204
|
className: i.userMessageScroll,
|
|
205
205
|
containerClass: i.userMessageScrollPort,
|
|
206
206
|
contentClass: i.parts,
|
|
207
|
-
|
|
208
|
-
expanded: p,
|
|
209
|
-
onPress: () => n((o) => !o),
|
|
210
|
-
labelExpand: C.expand,
|
|
211
|
-
labelCollapse: C.collapse,
|
|
212
|
-
className: i.userMessageExpandToggle
|
|
213
|
-
}),
|
|
214
|
-
"aria-expanded": p,
|
|
207
|
+
"aria-expanded": n,
|
|
215
208
|
children: t
|
|
216
|
-
})
|
|
209
|
+
}), /* @__PURE__ */ l(B, {
|
|
210
|
+
expanded: n,
|
|
211
|
+
onPress: () => p((o) => !o),
|
|
212
|
+
labelExpand: b.expand,
|
|
213
|
+
labelCollapse: b.collapse,
|
|
214
|
+
className: i.userMessageExpandToggle
|
|
215
|
+
})]
|
|
217
216
|
})]
|
|
218
217
|
});
|
|
219
218
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageUserBubble.js","sources":["../../../../src/chat/Message/turn/MessageUserBubble.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@reforma/lib';\nimport {\n attachedLayerRefKey,\n codeEditorStateKey,\n formatLayerCite,\n resolveLayerCite,\n type CodeEditorState,\n type SelectedLayerContext,\n} from '@reforma/types';\nimport { observer } from 'mobx-react-lite';\nimport { useState, type ReactNode } from 'react';\n\nimport { For } from '../../../For';\nimport { Scrollable, ScrollExpandChevronButton } from '../../../Scrollable';\nimport { Show } from '../../../Show';\nimport { Badge } from '../../../Tag/Badge';\nimport { useChat } from '../../ChatContext';\nimport { Chip, type ChipItem } from '../../Chip/Chip';\nimport { chipItemFromPath } from '../../Chip/helpers/chipPath';\nimport { fileChipDisplay, fileCite } from '../../Chip/helpers/cursorLines';\nimport { MessageText } from '../streamdown/MessageText';\nimport styles from './Message.module.css';\nimport { useMessageTurn } from './messageTurnContext';\n\nimport type { ReformaUserMessageMetadata } from '@reforma/types/sandbox';\n\nexport const MESSAGE_USER_COLLAPSE_MIN_CHARS = 500;\n\nconst USER_COLLAPSE_LABELS = {\n expand: 'Show full message',\n collapse: 'Show less',\n} as const;\n\ntype TextSegment = { type: 'text'; value: string };\ntype FileSegment = { type: 'file'; cite: string; file: CodeEditorState };\ntype LayerSegment = {\n type: 'layer';\n cite: string;\n layer: SelectedLayerContext;\n};\ntype CommandSegment = { type: 'command'; cite: string; skill: string };\ntype LinkSegment = { type: 'link'; cite: string; url: string; host: string };\ntype UserMessageSegment = TextSegment | FileSegment | LayerSegment | CommandSegment | LinkSegment;\n\nfunction fileCiteChipItem(file: CodeEditorState): ChipItem {\n const fromPath = chipItemFromPath(file.path);\n\n return {\n id: codeEditorStateKey(file),\n path: fromPath?.path ?? file.path,\n label: fileChipDisplay(file),\n tooltip: fromPath?.tooltip,\n ...(fromPath?.icon ? { icon: fromPath.icon } : {}),\n ...(file.cursor ? { cursor: file.cursor } : {}),\n };\n}\n\n/**\n * Split user prompt into text + chips for cites that appear in the prompt.\n * Forced meta pins (comment / ask-to-apply) stay in metadata for the agent — not rendered here.\n */\nfunction splitUserMessageSegments(\n text: string,\n metadata: ReformaUserMessageMetadata | undefined\n): UserMessageSegment[] {\n const files = metadata?.attached?.files ?? [];\n const layers = metadata?.attached?.layers ?? [];\n const slashNames = [...new Set([\n ...(metadata?.skills ?? []),\n ...(metadata?.commands ?? []),\n ])];\n\n const cites: Array<{ cite: string; segment: Exclude<UserMessageSegment, TextSegment> }> = [\n ...files.map((file) => {\n const cite = fileCite(file);\n\n return { cite, segment: { type: 'file' as const, cite, file } };\n }),\n ...layers.map((layer) => {\n const cite = formatLayerCite(layer);\n\n return { cite, segment: { type: 'layer' as const, cite, layer } };\n }),\n ...slashNames.map((raw) => {\n const name = raw.trim().replace(/^\\//, '');\n const cite = `/${ name }`;\n\n return { cite, segment: { type: 'command' as const, cite, skill: name } };\n }),\n ...[...text.matchAll(/@https?:\\/\\/[^\\s]+/gi)].map((match) => {\n const cite = match[0] ?? '';\n const url = cite.slice(1);\n let host = url;\n\n try {\n host = new URL(url).hostname.replace(/^www\\./, '') || url;\n }\n catch {\n // keep `url` as the chip label\n }\n\n return { cite, segment: { type: 'link' as const, cite, url, host } };\n }),\n ].sort((a, b) => b.cite.length - a.cite.length);\n\n if (cites.length === 0) {\n return text ? [{ type: 'text', value: text }] : [];\n }\n\n const segments: UserMessageSegment[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n let bestIdx = -1;\n let best: (typeof cites)[number] | undefined;\n\n for (const entry of cites) {\n const idx = remaining.indexOf(entry.cite);\n\n if (idx < 0) {\n continue;\n }\n\n if (\n bestIdx < 0\n || idx < bestIdx\n || (idx === bestIdx && entry.cite.length > (best?.cite.length ?? 0))\n ) {\n bestIdx = idx;\n best = entry;\n }\n }\n\n if (bestIdx < 0 || !best) {\n segments.push({ type: 'text', value: remaining });\n break;\n }\n\n if (bestIdx > 0) {\n segments.push({ type: 'text', value: remaining.slice(0, bestIdx) });\n }\n\n segments.push(best.segment);\n remaining = remaining.slice(bestIdx + best.cite.length);\n }\n\n return segments.filter(segment => segment.type !== 'text' || segment.value.length > 0);\n}\n\nfunction UserCiteChip({\n item,\n onOpenPath,\n}: {\n item: ChipItem;\n onOpenPath?: (item: ChipItem) => void;\n}): ReactNode {\n return (\n <Chip\n className={ styles.userCite }\n item={ item }\n onAction={ item.href ? undefined : onOpenPath }\n />\n );\n}\n\nfunction UserMessageBody({\n text,\n metadata,\n onOpenPath,\n}: {\n text: string;\n metadata: ReformaUserMessageMetadata | undefined;\n onOpenPath?: (item: ChipItem) => void;\n}): ReactNode {\n const segments = splitUserMessageSegments(text, metadata);\n\n if (segments.length === 0) {\n return null;\n }\n\n const hasCites = segments.some(segment => segment.type !== 'text');\n\n if (!hasCites && segments[0]?.type === 'text') {\n return (\n <MessageText\n className={ styles.userMessageBody }\n mode=\"static\"\n >\n { segments[0].value }\n </MessageText>\n );\n }\n\n return (\n <div className={ cn(styles.userMessageBody, styles.userMessageWithCites) }>\n <For each={ segments }>\n { (segment, index) => {\n if (segment.type === 'text') {\n return (\n <MessageText\n key={ `t-${ index }` }\n className={ styles.userMessageFragment }\n mode=\"static\"\n >\n { segment.value }\n </MessageText>\n );\n }\n\n if (segment.type === 'command') {\n return (\n <Badge\n key={ `c-${ segment.cite }-${ index }` }\n size=\"xs\"\n color=\"success\"\n value={ segment.skill }\n textValue={ segment.cite }\n aria-label={ segment.cite }\n className={ styles.userCite }\n >\n { segment.cite }\n </Badge>\n );\n }\n\n if (segment.type === 'file') {\n return (\n <UserCiteChip\n key={ `f-${ segment.cite }-${ index }` }\n item={ fileCiteChipItem(segment.file) }\n onOpenPath={ onOpenPath }\n />\n );\n }\n\n if (segment.type === 'link') {\n return (\n <UserCiteChip\n key={ `u-${ segment.cite }-${ index }` }\n item={ {\n id: segment.url,\n type: 'link',\n label: segment.host,\n tooltip: segment.url,\n href: segment.url,\n } }\n onOpenPath={ onOpenPath }\n />\n );\n }\n\n return (\n <UserCiteChip\n key={ `l-${ segment.cite }-${ index }` }\n item={ {\n id: attachedLayerRefKey(segment.layer),\n type: 'element',\n label: segment.layer.propName\n ? `${ resolveLayerCite(segment.layer) }.${ segment.layer.propName }`\n : (segment.layer.text || segment.layer.label || segment.layer.layerId),\n ...(segment.layer.icon ? { icon: segment.layer.icon } : {}),\n } }\n onOpenPath={ onOpenPath }\n />\n );\n } }\n </For>\n </div>\n );\n}\n\n/** User turn text bubble with collapsible long messages. Renders nothing when empty. */\nexport const MessageUserBubble = observer(() => {\n const turn = useMessageTurn();\n const { onOpenPath } = useChat();\n const [expanded, setExpanded] = useState(false);\n\n if (turn?.role !== 'user' || turn.message.role !== 'user') {\n return null;\n }\n\n const { text, message } = turn;\n const hasText = text.trim().length > 0;\n const hasAttached = Boolean(\n message.metadata?.attached?.files?.length\n || message.metadata?.attached?.layers?.length\n || message.metadata?.skills?.length\n || message.metadata?.commands?.length\n );\n\n if (!hasText && !hasAttached) {\n return null;\n }\n\n const body = (\n <UserMessageBody\n text={ text }\n metadata={ message.metadata }\n onOpenPath={ onOpenPath }\n />\n );\n const collapsible = text.length > MESSAGE_USER_COLLAPSE_MIN_CHARS;\n\n return (\n <div className={ cn(styles.messageBubble, styles.userBubble) }>\n <Show when={ !collapsible }>\n <div className={ styles.parts }>\n { body }\n </div>\n </Show>\n\n <Show when={ collapsible }>\n <Scrollable\n vertical\n edgeFade\n className={ styles.userMessageScroll }\n containerClass={ styles.userMessageScrollPort }\n contentClass={ styles.parts }\n overlay={ (\n <ScrollExpandChevronButton\n expanded={ expanded }\n onPress={ () => setExpanded(v => !v) }\n labelExpand={ USER_COLLAPSE_LABELS.expand }\n labelCollapse={ USER_COLLAPSE_LABELS.collapse }\n className={ styles.userMessageExpandToggle }\n />\n ) }\n aria-expanded={ expanded }\n >\n { body }\n </Scrollable>\n </Show>\n </div>\n );\n});\n"],"names":["MESSAGE_USER_COLLAPSE_MIN_CHARS","USER_COLLAPSE_LABELS","fileCiteChipItem","file","fromPath","chipItemFromPath","codeEditorStateKey","fileChipDisplay","splitUserMessageSegments","text","metadata","files","layers","slashNames","cites","cite","fileCite","layer","formatLayerCite","raw","name","match","url","host","a","b","segments","remaining","bestIdx","best","entry","idx","segment","UserCiteChip","item","onOpenPath","Chip","styles","UserMessageBody","MessageText","cn","For","index","Badge","attachedLayerRefKey","resolveLayerCite","MessageUserBubble","observer","turn","useMessageTurn","useChat","expanded","setExpanded","useState","message","hasText","hasAttached","body","collapsible","_jsx","Show","Scrollable","ScrollExpandChevronButton","v"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MessageUserBubble.js","sources":["../../../../src/chat/Message/turn/MessageUserBubble.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@reforma/lib';\nimport {\n attachedLayerRefKey,\n codeEditorStateKey,\n formatLayerCite,\n resolveLayerCite,\n type CodeEditorState,\n type SelectedLayerContext,\n} from '@reforma/types';\nimport { observer } from 'mobx-react-lite';\nimport { useState, type ReactNode } from 'react';\n\nimport { For } from '../../../For';\nimport { Scrollable, ScrollExpandChevronButton } from '../../../Scrollable';\nimport { Show } from '../../../Show';\nimport { Badge } from '../../../Tag/Badge';\nimport { useChat } from '../../ChatContext';\nimport { Chip, type ChipItem } from '../../Chip/Chip';\nimport { chipItemFromPath } from '../../Chip/helpers/chipPath';\nimport { fileChipDisplay, fileCite } from '../../Chip/helpers/cursorLines';\nimport { MessageText } from '../streamdown/MessageText';\nimport styles from './Message.module.css';\nimport { useMessageTurn } from './messageTurnContext';\n\nimport type { ReformaUserMessageMetadata } from '@reforma/types/sandbox';\n\nexport const MESSAGE_USER_COLLAPSE_MIN_CHARS = 500;\n\nconst USER_COLLAPSE_LABELS = {\n expand: 'Show full message',\n collapse: 'Show less',\n} as const;\n\ntype TextSegment = { type: 'text'; value: string };\ntype FileSegment = { type: 'file'; cite: string; file: CodeEditorState };\ntype LayerSegment = {\n type: 'layer';\n cite: string;\n layer: SelectedLayerContext;\n};\ntype CommandSegment = { type: 'command'; cite: string; skill: string };\ntype LinkSegment = { type: 'link'; cite: string; url: string; host: string };\ntype UserMessageSegment = TextSegment | FileSegment | LayerSegment | CommandSegment | LinkSegment;\n\nfunction fileCiteChipItem(file: CodeEditorState): ChipItem {\n const fromPath = chipItemFromPath(file.path);\n\n return {\n id: codeEditorStateKey(file),\n path: fromPath?.path ?? file.path,\n label: fileChipDisplay(file),\n tooltip: fromPath?.tooltip,\n ...(fromPath?.icon ? { icon: fromPath.icon } : {}),\n ...(file.cursor ? { cursor: file.cursor } : {}),\n };\n}\n\n/**\n * Split user prompt into text + chips for cites that appear in the prompt.\n * Forced meta pins (comment / ask-to-apply) stay in metadata for the agent — not rendered here.\n */\nfunction splitUserMessageSegments(\n text: string,\n metadata: ReformaUserMessageMetadata | undefined\n): UserMessageSegment[] {\n const files = metadata?.attached?.files ?? [];\n const layers = metadata?.attached?.layers ?? [];\n const slashNames = [...new Set([\n ...(metadata?.skills ?? []),\n ...(metadata?.commands ?? []),\n ])];\n\n const cites: Array<{ cite: string; segment: Exclude<UserMessageSegment, TextSegment> }> = [\n ...files.map((file) => {\n const cite = fileCite(file);\n\n return { cite, segment: { type: 'file' as const, cite, file } };\n }),\n ...layers.map((layer) => {\n const cite = formatLayerCite(layer);\n\n return { cite, segment: { type: 'layer' as const, cite, layer } };\n }),\n ...slashNames.map((raw) => {\n const name = raw.trim().replace(/^\\//, '');\n const cite = `/${ name }`;\n\n return { cite, segment: { type: 'command' as const, cite, skill: name } };\n }),\n ...[...text.matchAll(/@https?:\\/\\/[^\\s]+/gi)].map((match) => {\n const cite = match[0] ?? '';\n const url = cite.slice(1);\n let host = url;\n\n try {\n host = new URL(url).hostname.replace(/^www\\./, '') || url;\n }\n catch {\n // keep `url` as the chip label\n }\n\n return { cite, segment: { type: 'link' as const, cite, url, host } };\n }),\n ].sort((a, b) => b.cite.length - a.cite.length);\n\n if (cites.length === 0) {\n return text ? [{ type: 'text', value: text }] : [];\n }\n\n const segments: UserMessageSegment[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n let bestIdx = -1;\n let best: (typeof cites)[number] | undefined;\n\n for (const entry of cites) {\n const idx = remaining.indexOf(entry.cite);\n\n if (idx < 0) {\n continue;\n }\n\n if (\n bestIdx < 0\n || idx < bestIdx\n || (idx === bestIdx && entry.cite.length > (best?.cite.length ?? 0))\n ) {\n bestIdx = idx;\n best = entry;\n }\n }\n\n if (bestIdx < 0 || !best) {\n segments.push({ type: 'text', value: remaining });\n break;\n }\n\n if (bestIdx > 0) {\n segments.push({ type: 'text', value: remaining.slice(0, bestIdx) });\n }\n\n segments.push(best.segment);\n remaining = remaining.slice(bestIdx + best.cite.length);\n }\n\n return segments.filter(segment => segment.type !== 'text' || segment.value.length > 0);\n}\n\nfunction UserCiteChip({\n item,\n onOpenPath,\n}: {\n item: ChipItem;\n onOpenPath?: (item: ChipItem) => void;\n}): ReactNode {\n return (\n <Chip\n className={ styles.userCite }\n item={ item }\n onAction={ item.href ? undefined : onOpenPath }\n />\n );\n}\n\nfunction UserMessageBody({\n text,\n metadata,\n onOpenPath,\n}: {\n text: string;\n metadata: ReformaUserMessageMetadata | undefined;\n onOpenPath?: (item: ChipItem) => void;\n}): ReactNode {\n const segments = splitUserMessageSegments(text, metadata);\n\n if (segments.length === 0) {\n return null;\n }\n\n const hasCites = segments.some(segment => segment.type !== 'text');\n\n if (!hasCites && segments[0]?.type === 'text') {\n return (\n <MessageText\n className={ styles.userMessageBody }\n mode=\"static\"\n >\n { segments[0].value }\n </MessageText>\n );\n }\n\n return (\n <div className={ cn(styles.userMessageBody, styles.userMessageWithCites) }>\n <For each={ segments }>\n { (segment, index) => {\n if (segment.type === 'text') {\n return (\n <MessageText\n key={ `t-${ index }` }\n className={ styles.userMessageFragment }\n mode=\"static\"\n >\n { segment.value }\n </MessageText>\n );\n }\n\n if (segment.type === 'command') {\n return (\n <Badge\n key={ `c-${ segment.cite }-${ index }` }\n size=\"xs\"\n color=\"success\"\n value={ segment.skill }\n textValue={ segment.cite }\n aria-label={ segment.cite }\n className={ styles.userCite }\n >\n { segment.cite }\n </Badge>\n );\n }\n\n if (segment.type === 'file') {\n return (\n <UserCiteChip\n key={ `f-${ segment.cite }-${ index }` }\n item={ fileCiteChipItem(segment.file) }\n onOpenPath={ onOpenPath }\n />\n );\n }\n\n if (segment.type === 'link') {\n return (\n <UserCiteChip\n key={ `u-${ segment.cite }-${ index }` }\n item={ {\n id: segment.url,\n type: 'link',\n label: segment.host,\n tooltip: segment.url,\n href: segment.url,\n } }\n onOpenPath={ onOpenPath }\n />\n );\n }\n\n return (\n <UserCiteChip\n key={ `l-${ segment.cite }-${ index }` }\n item={ {\n id: attachedLayerRefKey(segment.layer),\n type: 'element',\n label: segment.layer.propName\n ? `${ resolveLayerCite(segment.layer) }.${ segment.layer.propName }`\n : (segment.layer.text || segment.layer.label || segment.layer.layerId),\n ...(segment.layer.icon ? { icon: segment.layer.icon } : {}),\n } }\n onOpenPath={ onOpenPath }\n />\n );\n } }\n </For>\n </div>\n );\n}\n\n/** User turn text bubble with collapsible long messages. Renders nothing when empty. */\nexport const MessageUserBubble = observer(() => {\n const turn = useMessageTurn();\n const { onOpenPath } = useChat();\n const [expanded, setExpanded] = useState(false);\n\n if (turn?.role !== 'user' || turn.message.role !== 'user') {\n return null;\n }\n\n const { text, message } = turn;\n const hasText = text.trim().length > 0;\n const hasAttached = Boolean(\n message.metadata?.attached?.files?.length\n || message.metadata?.attached?.layers?.length\n || message.metadata?.skills?.length\n || message.metadata?.commands?.length\n );\n\n if (!hasText && !hasAttached) {\n return null;\n }\n\n const body = (\n <UserMessageBody\n text={ text }\n metadata={ message.metadata }\n onOpenPath={ onOpenPath }\n />\n );\n const collapsible = text.length > MESSAGE_USER_COLLAPSE_MIN_CHARS;\n\n return (\n <div className={ cn(styles.messageBubble, styles.userBubble) }>\n <Show when={ !collapsible }>\n <div className={ styles.parts }>\n { body }\n </div>\n </Show>\n\n <Show when={ collapsible }>\n <Scrollable\n vertical\n edgeFade={ !expanded }\n className={ styles.userMessageScroll }\n containerClass={ styles.userMessageScrollPort }\n contentClass={ styles.parts }\n aria-expanded={ expanded }\n >\n { body }\n </Scrollable>\n <ScrollExpandChevronButton\n expanded={ expanded }\n onPress={ () => setExpanded(v => !v) }\n labelExpand={ USER_COLLAPSE_LABELS.expand }\n labelCollapse={ USER_COLLAPSE_LABELS.collapse }\n className={ styles.userMessageExpandToggle }\n />\n </Show>\n </div>\n );\n});\n"],"names":["MESSAGE_USER_COLLAPSE_MIN_CHARS","USER_COLLAPSE_LABELS","fileCiteChipItem","file","fromPath","chipItemFromPath","codeEditorStateKey","fileChipDisplay","splitUserMessageSegments","text","metadata","files","layers","slashNames","cites","cite","fileCite","layer","formatLayerCite","raw","name","match","url","host","a","b","segments","remaining","bestIdx","best","entry","idx","segment","UserCiteChip","item","onOpenPath","Chip","styles","UserMessageBody","MessageText","cn","For","index","Badge","attachedLayerRefKey","resolveLayerCite","MessageUserBubble","observer","turn","useMessageTurn","useChat","expanded","setExpanded","useState","message","hasText","hasAttached","body","collapsible","_jsx","Show","_jsxs","Scrollable","ScrollExpandChevronButton","v"],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MessageSegment } from '../normalize/normalizeMessageParts';
|
|
2
|
+
export type FinishedWorkSplit = {
|
|
3
|
+
work: readonly MessageSegment[];
|
|
4
|
+
answer: MessageSegment;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Finished turn whose last visible part is text: tuck every segment before that
|
|
8
|
+
* answer under one disclosure. Streaming, cancelled, and "still waiting" turns stay open.
|
|
9
|
+
*/
|
|
10
|
+
export declare function splitFinishedWork(segments: readonly MessageSegment[], flags: {
|
|
11
|
+
streaming: boolean;
|
|
12
|
+
cancelled: boolean;
|
|
13
|
+
}): FinishedWorkSplit | null;
|
|
14
|
+
/** "Worked for 25s" / "Worked for 2m". "Worked" when the turn has no timestamps. */
|
|
15
|
+
export declare function workedForLabel(startedAt: number | undefined, endedAt: number | undefined): string;
|
|
16
|
+
//# sourceMappingURL=workedCollapse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workedCollapse.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/turn/workedCollapse.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,MAAM,MAAM,iBAAiB,GAAG;IAC5B,IAAI,EAAE,SAAS,cAAc,EAAE,CAAC;IAChC,MAAM,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,iBAAiB,CAC7B,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,KAAK,EAAE;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GAClD,iBAAiB,GAAG,IAAI,CAyB1B;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAgCjG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { isTextUIPart as l } from "ai";
|
|
2
|
+
import { segmentRequiresUserAction as s, lastVisiblePartFromGroups as f } from "../normalize/normalizeMessageParts.js";
|
|
3
|
+
function a(r, e) {
|
|
4
|
+
if (e.streaming || e.cancelled || r.length < 2 || r.some((i) => s(i.groups)))
|
|
5
|
+
return null;
|
|
6
|
+
const n = r[r.length - 1];
|
|
7
|
+
if (!n || n.layout !== "ungrouped")
|
|
8
|
+
return null;
|
|
9
|
+
const o = f(n.groups);
|
|
10
|
+
return !o || !l(o) || o.state === "streaming" || !o.text.trim() ? null : {
|
|
11
|
+
work: r.slice(0, -1),
|
|
12
|
+
answer: n
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function h(r, e) {
|
|
16
|
+
if (r == null || e == null || !Number.isFinite(r) || !Number.isFinite(e) || e < r)
|
|
17
|
+
return "Worked";
|
|
18
|
+
const n = Math.max(1, Math.round((e - r) / 1e3));
|
|
19
|
+
if (n < 60)
|
|
20
|
+
return `Worked for ${n}s`;
|
|
21
|
+
const o = Math.floor(n / 60), i = n % 60;
|
|
22
|
+
if (o < 60)
|
|
23
|
+
return i === 0 ? `Worked for ${o}m` : `Worked for ${o}m ${i}s`;
|
|
24
|
+
const t = Math.floor(o / 60), u = o % 60;
|
|
25
|
+
return u === 0 ? `Worked for ${t}h` : `Worked for ${t}h ${u}m`;
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
a as splitFinishedWork,
|
|
29
|
+
h as workedForLabel
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=workedCollapse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workedCollapse.js","sources":["../../../../src/chat/Message/turn/workedCollapse.ts"],"sourcesContent":["import { isTextUIPart } from 'ai';\n\nimport {\n lastVisiblePartFromGroups,\n segmentRequiresUserAction,\n} from '../normalize/normalizeMessageParts';\n\nimport type { MessageSegment } from '../normalize/normalizeMessageParts';\n\nexport type FinishedWorkSplit = {\n work: readonly MessageSegment[];\n answer: MessageSegment;\n};\n\n/**\n * Finished turn whose last visible part is text: tuck every segment before that\n * answer under one disclosure. Streaming, cancelled, and \"still waiting\" turns stay open.\n */\nexport function splitFinishedWork(\n segments: readonly MessageSegment[],\n flags: { streaming: boolean; cancelled: boolean }\n): FinishedWorkSplit | null {\n if (flags.streaming || flags.cancelled || segments.length < 2) {\n return null;\n }\n\n if (segments.some(segment => segmentRequiresUserAction(segment.groups))) {\n return null;\n }\n\n const answer = segments[segments.length - 1];\n\n if (!answer || answer.layout !== 'ungrouped') {\n return null;\n }\n\n const tail = lastVisiblePartFromGroups(answer.groups);\n\n if (!tail || !isTextUIPart(tail) || tail.state === 'streaming' || !tail.text.trim()) {\n return null;\n }\n\n return {\n work: segments.slice(0, -1),\n answer,\n };\n}\n\n/** \"Worked for 25s\" / \"Worked for 2m\". \"Worked\" when the turn has no timestamps. */\nexport function workedForLabel(startedAt: number | undefined, endedAt: number | undefined): string {\n if (\n startedAt == null\n || endedAt == null\n || !Number.isFinite(startedAt)\n || !Number.isFinite(endedAt)\n || endedAt < startedAt\n ) {\n return 'Worked';\n }\n\n const seconds = Math.max(1, Math.round((endedAt - startedAt) / 1000));\n\n if (seconds < 60) {\n return `Worked for ${ seconds }s`;\n }\n\n const minutes = Math.floor(seconds / 60);\n const remSeconds = seconds % 60;\n\n if (minutes < 60) {\n return remSeconds === 0\n ? `Worked for ${ minutes }m`\n : `Worked for ${ minutes }m ${ remSeconds }s`;\n }\n\n const hours = Math.floor(minutes / 60);\n const remMinutes = minutes % 60;\n\n return remMinutes === 0\n ? `Worked for ${ hours }h`\n : `Worked for ${ hours }h ${ remMinutes }m`;\n}\n"],"names":["splitFinishedWork","segments","flags","segment","segmentRequiresUserAction","answer","tail","lastVisiblePartFromGroups","isTextUIPart","workedForLabel","startedAt","endedAt","seconds","minutes","remSeconds","hours","remMinutes"],"mappings":";;AAMO,SAASA,EAAkBC,GAAUC,GAAO;AAIjD,MAHIA,EAAM,aAAaA,EAAM,aAAaD,EAAS,SAAS,KAGxDA,EAAS,KAAK,CAAAE,MAAWC,EAA0BD,EAAQ,MAAM,CAAC;AACpE,WAAO;AAET,QAAME,IAASJ,EAASA,EAAS,SAAS,CAAC;AAC3C,MAAI,CAACI,KAAUA,EAAO,WAAW;AAC/B,WAAO;AAET,QAAMC,IAAOC,EAA0BF,EAAO,MAAM;AACpD,SAAI,CAACC,KAAQ,CAACE,EAAaF,CAAI,KAAKA,EAAK,UAAU,eAAe,CAACA,EAAK,KAAK,SACpE,OAEF;AAAA,IACL,MAAML,EAAS,MAAM,GAAG,EAAE;AAAA,IAC1B,QAAAI;AAAA,EAAA;AAEJ;AAGO,SAASI,EAAeC,GAAWC,GAAS;AACjD,MAAID,KAAa,QAAQC,KAAW,QAAQ,CAAC,OAAO,SAASD,CAAS,KAAK,CAAC,OAAO,SAASC,CAAO,KAAKA,IAAUD;AAChH,WAAO;AAET,QAAME,IAAU,KAAK,IAAI,GAAG,KAAK,OAAOD,IAAUD,KAAa,GAAI,CAAC;AACpE,MAAIE,IAAU;AACZ,WAAO,cAAcA,CAAO;AAE9B,QAAMC,IAAU,KAAK,MAAMD,IAAU,EAAE,GACjCE,IAAaF,IAAU;AAC7B,MAAIC,IAAU;AACZ,WAAOC,MAAe,IAAI,cAAcD,CAAO,MAAM,cAAcA,CAAO,KAAKC,CAAU;AAE3F,QAAMC,IAAQ,KAAK,MAAMF,IAAU,EAAE,GAC/BG,IAAaH,IAAU;AAC7B,SAAOG,MAAe,IAAI,cAAcD,CAAK,MAAM,cAAcA,CAAK,KAAKC,CAAU;AACvF;"}
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import type { ToolRendererProps } from '../types';
|
|
2
|
+
/** One composer strip: who is running, and the child thread Show opens. */
|
|
3
|
+
export declare function subagentComposerCopy(part: {
|
|
4
|
+
input?: unknown;
|
|
5
|
+
output?: unknown;
|
|
6
|
+
}, patch: Record<string, unknown> | undefined): {
|
|
7
|
+
text: string;
|
|
8
|
+
label: string;
|
|
9
|
+
childThreadId?: string;
|
|
10
|
+
waiting: boolean;
|
|
11
|
+
};
|
|
2
12
|
/** Live subtitle for a tool — same copy for Agent rows and the compact rail task. */
|
|
3
13
|
export declare function subagentActivityLabel(patch: Record<string, unknown> | undefined): string | undefined;
|
|
4
14
|
/** Live/waiting subtitle. Done rows stay quiet — no empty "Completed". */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentTool.d.ts","sourceRoot":"","sources":["../../../../src/chat/Tool/agent/AgentTool.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AA6IlD,qFAAqF;AACrF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CA0BpG;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,MAAM,GAAG,SAAS,CAcrB;AAiFD,mDAAmD;AACnD,eAAO,MAAM,SAAS,cAAuB,iBAAiB;8BAAjB,iBAAiB;CA6C5D,CAAC"}
|
|
1
|
+
{"version":3,"file":"AgentTool.d.ts","sourceRoot":"","sources":["../../../../src/chat/Tool/agent/AgentTool.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AA6IlD,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAChC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,EAC3C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC3C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAmB3E;AAED,qFAAqF;AACrF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CA0BpG;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,MAAM,GAAG,SAAS,CAcrB;AAiFD,mDAAmD;AACnD,eAAO,MAAM,SAAS,cAAuB,iBAAiB;8BAAjB,iBAAiB;CA6C5D,CAAC"}
|