@reforma/components 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/RichInput/RichInput.d.ts +1 -1
- package/dist/RichInput/RichInput.d.ts.map +1 -1
- package/dist/RichInput/RichInput.js +126 -123
- package/dist/RichInput/RichInput.js.map +1 -1
- package/dist/chat/ComposerBanner/ComposerBanner.d.ts +6 -1
- package/dist/chat/ComposerBanner/ComposerBanner.d.ts.map +1 -1
- package/dist/chat/ComposerBanner/ComposerBanner.js +60 -40
- package/dist/chat/ComposerBanner/ComposerBanner.js.map +1 -1
- package/dist/chat/ComposerBanner/ComposerBanner.module.css +1 -1
- package/dist/chat/ComposerBanner/ComposerBanner.module.css.js +13 -9
- package/dist/chat/ComposerBanner/ComposerBanner.module.css.js.map +1 -1
- package/dist/chat/Conversation/ConversationPendingLoader.d.ts.map +1 -1
- package/dist/chat/Conversation/ConversationPendingLoader.js +1 -1
- package/dist/chat/Conversation/ConversationPendingLoader.js.map +1 -1
- package/dist/chat/Message/normalize/normalizeMessageParts.d.ts +1 -1
- package/dist/chat/Message/normalize/normalizeMessageParts.d.ts.map +1 -1
- package/dist/chat/Message/normalize/normalizeMessageParts.js +1 -1
- package/dist/chat/Message/normalize/normalizeMessageParts.js.map +1 -1
- package/dist/chat/Message/parts/MessagePart.d.ts.map +1 -1
- package/dist/chat/Message/parts/MessagePart.js +1 -1
- package/dist/chat/Message/parts/MessagePart.js.map +1 -1
- package/dist/chat/Message/parts/backgroundResultPart.js +1 -1
- package/dist/chat/Message/parts/backgroundResultPart.js.map +1 -1
- package/dist/chat/Message/parts/collectMessageSources.d.ts +1 -1
- package/dist/chat/Message/parts/collectMessageSources.d.ts.map +1 -1
- package/dist/chat/Message/parts/collectMessageSources.js +1 -1
- package/dist/chat/Message/parts/collectMessageSources.js.map +1 -1
- package/dist/chat/Message/parts/contextCompactionPart.js +1 -1
- package/dist/chat/Message/parts/contextCompactionPart.js.map +1 -1
- package/dist/chat/Message/segments/analyzeGroupedSegment.js +5 -5
- package/dist/chat/Message/segments/analyzeGroupedSegment.js.map +1 -1
- package/dist/chat/Message/segments/recentStreamingPhaseToolGroups.js +1 -1
- package/dist/chat/Message/segments/recentStreamingPhaseToolGroups.js.map +1 -1
- package/dist/chat/Message/turn/workedCollapse.js +1 -1
- package/dist/chat/Message/turn/workedCollapse.js.map +1 -1
- package/dist/chat/Tool/Tool.js +1 -1
- package/dist/chat/Tool/Tool.js.map +1 -1
- package/dist/chat/Tool/agent/AgentTool.d.ts.map +1 -1
- package/dist/chat/Tool/agent/AgentTool.js +73 -73
- package/dist/chat/Tool/agent/AgentTool.js.map +1 -1
- package/dist/chat/Tool/bash/BashTool.d.ts.map +1 -1
- package/dist/chat/Tool/bash/BashTool.js +1 -1
- package/dist/chat/Tool/bash/BashTool.js.map +1 -1
- package/dist/chat/Tool/create-directory/CreateDirectoryTool.js +1 -1
- package/dist/chat/Tool/create-directory/CreateDirectoryTool.js.map +1 -1
- package/dist/chat/Tool/default/Default.d.ts.map +1 -1
- package/dist/chat/Tool/default/Default.js +1 -1
- package/dist/chat/Tool/default/Default.js.map +1 -1
- package/dist/chat/Tool/dev-server/DevServerRestartTool.js +1 -1
- package/dist/chat/Tool/dev-server/DevServerRestartTool.js.map +1 -1
- package/dist/chat/Tool/dev-server/DevServerStatusTool.js +1 -1
- package/dist/chat/Tool/dev-server/DevServerStatusTool.js.map +1 -1
- package/dist/chat/Tool/edit/EditTool.js +1 -1
- package/dist/chat/Tool/edit/EditTool.js.map +1 -1
- package/dist/chat/Tool/fetch/FetchTool.js +1 -1
- package/dist/chat/Tool/fetch/FetchTool.js.map +1 -1
- package/dist/chat/Tool/fileChangesFromToolParts.js +1 -1
- package/dist/chat/Tool/fileChangesFromToolParts.js.map +1 -1
- package/dist/chat/Tool/get-background-result/GetBackgroundResultTool.js +1 -1
- package/dist/chat/Tool/get-background-result/GetBackgroundResultTool.js.map +1 -1
- package/dist/chat/Tool/get-errors/GetErrorsTool.js +1 -1
- package/dist/chat/Tool/get-errors/GetErrorsTool.js.map +1 -1
- package/dist/chat/Tool/glob/GlobTool.js +1 -1
- package/dist/chat/Tool/glob/GlobTool.js.map +1 -1
- package/dist/chat/Tool/grep/GrepTool.js +1 -1
- package/dist/chat/Tool/grep/GrepTool.js.map +1 -1
- package/dist/chat/Tool/helpers.d.ts +1 -1
- package/dist/chat/Tool/helpers.d.ts.map +1 -1
- package/dist/chat/Tool/helpers.js +1 -1
- package/dist/chat/Tool/helpers.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/install-dependencies/InstallDependenciesTool.js +1 -1
- package/dist/chat/Tool/install-dependencies/InstallDependenciesTool.js.map +1 -1
- package/dist/chat/Tool/install-plugin/InstallPlugin.js +1 -1
- package/dist/chat/Tool/install-plugin/InstallPlugin.js.map +1 -1
- package/dist/chat/Tool/integration-card/IntegrationActionCard.d.ts +3 -1
- package/dist/chat/Tool/integration-card/IntegrationActionCard.d.ts.map +1 -1
- package/dist/chat/Tool/integration-card/IntegrationActionCard.js +88 -82
- package/dist/chat/Tool/integration-card/IntegrationActionCard.js.map +1 -1
- package/dist/chat/Tool/list-directory/normalizeListDirectoryTools.js +1 -1
- package/dist/chat/Tool/list-directory/normalizeListDirectoryTools.js.map +1 -1
- package/dist/chat/Tool/mcp-tools/CallDynamicTool.js +1 -1
- package/dist/chat/Tool/mcp-tools/CallDynamicTool.js.map +1 -1
- package/dist/chat/Tool/mcp-tools/GetDynamicToolsTool.js +1 -1
- package/dist/chat/Tool/mcp-tools/GetDynamicToolsTool.js.map +1 -1
- package/dist/chat/Tool/mcp-tools/GetMcpResourcesTool.js +1 -1
- package/dist/chat/Tool/mcp-tools/GetMcpResourcesTool.js.map +1 -1
- package/dist/chat/Tool/mcp-tools/McpAuth.js +1 -1
- package/dist/chat/Tool/mcp-tools/McpAuth.js.map +1 -1
- package/dist/chat/Tool/memory/MemoryTool.js +1 -1
- package/dist/chat/Tool/memory/MemoryTool.js.map +1 -1
- package/dist/chat/Tool/move-file/MoveFileTool.js +1 -1
- package/dist/chat/Tool/move-file/MoveFileTool.js.map +1 -1
- package/dist/chat/Tool/plan/CreatePlanTool.js +1 -1
- package/dist/chat/Tool/plan/CreatePlanTool.js.map +1 -1
- package/dist/chat/Tool/preamble/PreambleTool.js +1 -1
- package/dist/chat/Tool/preamble/PreambleTool.js.map +1 -1
- package/dist/chat/Tool/project-build/BuildTool.js +1 -1
- package/dist/chat/Tool/project-build/BuildTool.js.map +1 -1
- package/dist/chat/Tool/project-env/ProjectEnvTool.js +1 -1
- package/dist/chat/Tool/project-env/ProjectEnvTool.js.map +1 -1
- package/dist/chat/Tool/read/normalizeReadTools.js +1 -1
- package/dist/chat/Tool/read/normalizeReadTools.js.map +1 -1
- package/dist/chat/Tool/read-lints/ReadLintsTool.js +1 -1
- package/dist/chat/Tool/read-lints/ReadLintsTool.js.map +1 -1
- package/dist/chat/Tool/remove-file/RemoveFileTool.js +1 -1
- package/dist/chat/Tool/remove-file/RemoveFileTool.js.map +1 -1
- package/dist/chat/Tool/scaffold-project/ScaffoldProjectTool.js +1 -1
- package/dist/chat/Tool/scaffold-project/ScaffoldProjectTool.js.map +1 -1
- package/dist/chat/Tool/screenshot/CaptureScreenshotTool.js +3 -3
- package/dist/chat/Tool/screenshot/CaptureScreenshotTool.js.map +1 -1
- package/dist/chat/Tool/skill/SkillTool.js +1 -1
- package/dist/chat/Tool/skill/SkillTool.js.map +1 -1
- package/dist/chat/Tool/waiting/WaitingTool.js +1 -1
- package/dist/chat/Tool/waiting/WaitingTool.js.map +1 -1
- package/dist/chat/Tool/web-search/WebSearchTool.js +1 -1
- package/dist/chat/Tool/web-search/WebSearchTool.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ButtonColor } from '../../Button';
|
|
1
2
|
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
3
|
export type ComposerBannerProps = Omit<HTMLAttributes<HTMLDivElement>, 'color'> & {
|
|
3
4
|
children?: ReactNode;
|
|
@@ -10,8 +11,12 @@ export type ComposerBannerStatusProps = HTMLAttributes<HTMLDivElement> & {
|
|
|
10
11
|
children: ReactNode;
|
|
11
12
|
action: string;
|
|
12
13
|
onAction?: () => void;
|
|
14
|
+
/** Action button tint. Default `secondary`. */
|
|
15
|
+
actionColor?: ButtonColor;
|
|
16
|
+
/** Press anywhere on the row except the action. */
|
|
17
|
+
onPress?: () => void;
|
|
13
18
|
icon?: ReactNode;
|
|
14
19
|
};
|
|
15
20
|
/** One status row inside {@link ComposerBanner} — message + action. */
|
|
16
|
-
export declare function ComposerBannerStatus({ children, action, onAction, icon, className, ...props }: ComposerBannerStatusProps): import("react").JSX.Element;
|
|
21
|
+
export declare function ComposerBannerStatus({ children, action, onAction, actionColor, onPress, icon, className, ...props }: ComposerBannerStatusProps): import("react").JSX.Element;
|
|
17
22
|
//# sourceMappingURL=ComposerBanner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComposerBanner.d.ts","sourceRoot":"","sources":["../../../src/chat/ComposerBanner/ComposerBanner.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ComposerBanner.d.ts","sourceRoot":"","sources":["../../../src/chat/ComposerBanner/ComposerBanner.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAMxD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvD,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,GAAG;IAC9E,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,yDAAyD;IACzD,KAAK,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF,qDAAqD;AACrD,wBAAgB,cAAc,CAAC,EAC3B,QAAQ,EACR,SAAS,EACT,KAAK,EACL,IAAI,EACJ,GAAG,KAAK,EACX,EAAE,mBAAmB,+BAYrB;AAED,MAAM,MAAM,yBAAyB,GAAG,cAAc,CAAC,cAAc,CAAC,GAAG;IACrE,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAEF,uEAAuE;AACvE,wBAAgB,oBAAoB,CAAC,EACjC,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,WAAyB,EACzB,OAAO,EACP,IAAI,EACJ,SAAS,EACT,GAAG,KAAK,EACX,EAAE,yBAAyB,+BAsC3B"}
|
|
@@ -1,58 +1,78 @@
|
|
|
1
|
-
import { cn as
|
|
2
|
-
import { Button as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { cn as d } from "@reforma/lib";
|
|
2
|
+
import { Button as u } from "../../Button/Button.js";
|
|
3
|
+
import { Pressable as x } from "react-aria-components";
|
|
4
|
+
import { Show as m } from "../../Show/Show.js";
|
|
5
|
+
import { Text as b } from "../../Text/Text.js";
|
|
5
6
|
import e from "./ComposerBanner.module.css.js";
|
|
6
|
-
import { jsx as
|
|
7
|
-
function
|
|
8
|
-
children:
|
|
9
|
-
className:
|
|
10
|
-
color:
|
|
11
|
-
role:
|
|
12
|
-
...
|
|
7
|
+
import { jsx as r, jsxs as c, Fragment as v } from "react/jsx-runtime";
|
|
8
|
+
function P({
|
|
9
|
+
children: o,
|
|
10
|
+
className: t,
|
|
11
|
+
color: s,
|
|
12
|
+
role: n,
|
|
13
|
+
...a
|
|
13
14
|
}) {
|
|
14
|
-
return /* @__PURE__ */
|
|
15
|
+
return /* @__PURE__ */ r("div", {
|
|
15
16
|
"data-slot": "composer-banner",
|
|
16
|
-
"data-color":
|
|
17
|
-
role:
|
|
18
|
-
className:
|
|
19
|
-
...
|
|
20
|
-
children:
|
|
17
|
+
"data-color": s,
|
|
18
|
+
role: n ?? (s === "danger" ? "alert" : void 0),
|
|
19
|
+
className: d(e.root, t),
|
|
20
|
+
...a,
|
|
21
|
+
children: o
|
|
21
22
|
});
|
|
22
23
|
}
|
|
23
|
-
function
|
|
24
|
-
children:
|
|
25
|
-
action:
|
|
26
|
-
onAction:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
function S({
|
|
25
|
+
children: o,
|
|
26
|
+
action: t,
|
|
27
|
+
onAction: s,
|
|
28
|
+
actionColor: n = "secondary",
|
|
29
|
+
onPress: a,
|
|
30
|
+
icon: i,
|
|
31
|
+
className: p,
|
|
32
|
+
...h
|
|
30
33
|
}) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
when: s,
|
|
36
|
-
children: /* @__PURE__ */ o("span", {
|
|
34
|
+
const l = /* @__PURE__ */ c(v, {
|
|
35
|
+
children: [/* @__PURE__ */ r(m, {
|
|
36
|
+
when: i,
|
|
37
|
+
children: /* @__PURE__ */ r("span", {
|
|
37
38
|
className: e.icon,
|
|
38
|
-
children:
|
|
39
|
+
children: i
|
|
39
40
|
})
|
|
40
|
-
}), /* @__PURE__ */
|
|
41
|
+
}), /* @__PURE__ */ r(b, {
|
|
41
42
|
variant: "xs",
|
|
42
43
|
className: e.text,
|
|
43
|
-
children:
|
|
44
|
-
})
|
|
44
|
+
children: o
|
|
45
|
+
})]
|
|
46
|
+
});
|
|
47
|
+
return /* @__PURE__ */ c("div", {
|
|
48
|
+
className: d(e.status, p),
|
|
49
|
+
"data-pressable": a ? !0 : void 0,
|
|
50
|
+
...h,
|
|
51
|
+
children: [/* @__PURE__ */ r(m, {
|
|
52
|
+
when: a,
|
|
53
|
+
fallback: l,
|
|
54
|
+
children: (f) => /* @__PURE__ */ r(x, {
|
|
55
|
+
onPress: f,
|
|
56
|
+
children: /* @__PURE__ */ r("span", {
|
|
57
|
+
role: "button",
|
|
58
|
+
tabIndex: 0,
|
|
59
|
+
className: e.press,
|
|
60
|
+
children: l
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
}), /* @__PURE__ */ r(u, {
|
|
45
64
|
size: "xs",
|
|
46
65
|
variant: "ghost",
|
|
47
|
-
color:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
66
|
+
color: n,
|
|
67
|
+
className: e.action,
|
|
68
|
+
isDisabled: !s,
|
|
69
|
+
onPress: s,
|
|
70
|
+
children: t
|
|
51
71
|
})]
|
|
52
72
|
});
|
|
53
73
|
}
|
|
54
74
|
export {
|
|
55
|
-
|
|
56
|
-
|
|
75
|
+
P as ComposerBanner,
|
|
76
|
+
S as ComposerBannerStatus
|
|
57
77
|
};
|
|
58
78
|
//# sourceMappingURL=ComposerBanner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComposerBanner.js","sources":["../../../src/chat/ComposerBanner/ComposerBanner.tsx"],"sourcesContent":["import { cn } from '@reforma/lib';\n\nimport { Button } from '../../Button';\nimport { Show } from '../../Show';\nimport { Text } from '../../Text';\nimport styles from './ComposerBanner.module.css';\n\nimport type { HTMLAttributes, ReactNode } from 'react';\n\nexport type ComposerBannerProps = Omit<HTMLAttributes<HTMLDivElement>, 'color'> & {\n children?: ReactNode;\n /** Plate tint. Default is the muted interrupt chrome. */\n color?: 'danger';\n};\n\n/** Shared plate above the composer — chrome only. */\nexport function ComposerBanner({\n children,\n className,\n color,\n role,\n ...props\n}: ComposerBannerProps) {\n return (\n <div\n data-slot=\"composer-banner\"\n data-color={ color }\n role={ role ?? (color === 'danger' ? 'alert' : undefined) }\n className={ cn(styles.root, className) }\n { ...props }\n >\n { children }\n </div>\n );\n}\n\nexport type ComposerBannerStatusProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n action: string;\n onAction?: () => void;\n icon?: ReactNode;\n};\n\n/** One status row inside {@link ComposerBanner} — message + action. */\nexport function ComposerBannerStatus({\n children,\n action,\n onAction,\n icon,\n className,\n ...props\n}: ComposerBannerStatusProps) {\n
|
|
1
|
+
{"version":3,"file":"ComposerBanner.js","sources":["../../../src/chat/ComposerBanner/ComposerBanner.tsx"],"sourcesContent":["import { cn } from '@reforma/lib';\n\nimport { Button, type ButtonColor } from '../../Button';\nimport { Pressable } from '../../Pressable';\nimport { Show } from '../../Show';\nimport { Text } from '../../Text';\nimport styles from './ComposerBanner.module.css';\n\nimport type { HTMLAttributes, ReactNode } from 'react';\n\nexport type ComposerBannerProps = Omit<HTMLAttributes<HTMLDivElement>, 'color'> & {\n children?: ReactNode;\n /** Plate tint. Default is the muted interrupt chrome. */\n color?: 'danger';\n};\n\n/** Shared plate above the composer — chrome only. */\nexport function ComposerBanner({\n children,\n className,\n color,\n role,\n ...props\n}: ComposerBannerProps) {\n return (\n <div\n data-slot=\"composer-banner\"\n data-color={ color }\n role={ role ?? (color === 'danger' ? 'alert' : undefined) }\n className={ cn(styles.root, className) }\n { ...props }\n >\n { children }\n </div>\n );\n}\n\nexport type ComposerBannerStatusProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n action: string;\n onAction?: () => void;\n /** Action button tint. Default `secondary`. */\n actionColor?: ButtonColor;\n /** Press anywhere on the row except the action. */\n onPress?: () => void;\n icon?: ReactNode;\n};\n\n/** One status row inside {@link ComposerBanner} — message + action. */\nexport function ComposerBannerStatus({\n children,\n action,\n onAction,\n actionColor = 'secondary',\n onPress,\n icon,\n className,\n ...props\n}: ComposerBannerStatusProps) {\n const message = (\n <>\n <Show when={ icon }>\n <span className={ styles.icon }>\n { icon }\n </span>\n </Show>\n <Text variant=\"xs\" className={ styles.text }>\n { children }\n </Text>\n </>\n );\n\n return (\n <div className={ cn(styles.status, className) } data-pressable={ onPress ? true : undefined } { ...props }>\n <Show when={ onPress } fallback={ message }>\n { press => (\n <Pressable onPress={ press }>\n <span role=\"button\" tabIndex={ 0 } className={ styles.press }>\n { message }\n </span>\n </Pressable>\n ) }\n </Show>\n\n <Button\n size=\"xs\"\n variant=\"ghost\"\n color={ actionColor }\n className={ styles.action }\n isDisabled={ !onAction }\n onPress={ onAction }\n >\n { action }\n </Button>\n </div>\n );\n}\n"],"names":["ComposerBanner","children","className","color","role","props","cn","styles","ComposerBannerStatus","action","onAction","actionColor","onPress","icon","message","_Fragment","_jsx","Show","Text","press","Pressable","Button"],"mappings":";;;;;;;AAQO,SAASA,EAAe;AAAA,EAC7B,UAAAC;AAAA,EACA,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,MAAAC;AAAA,EACA,GAAGC;AACL,GAAG;AACD,2BAAyB,OAAO;AAAA,IAC9B,aAAa;AAAA,IACb,cAAcF;AAAA,IACd,MAAMC,MAASD,MAAU,WAAW,UAAU;AAAA,IAC9C,WAAWG,EAAGC,EAAO,MAAML,CAAS;AAAA,IACpC,GAAGG;AAAA,IACH,UAAAJ;AAAA,EAAA,CACD;AACH;AAEO,SAASO,EAAqB;AAAA,EACnC,UAAAP;AAAA,EACA,QAAAQ;AAAA,EACA,UAAAC;AAAA,EACA,aAAAC,IAAc;AAAA,EACd,SAAAC;AAAA,EACA,MAAAC;AAAA,EACA,WAAAX;AAAA,EACA,GAAGG;AACL,GAAG;AACD,QAAMS,sBAA6BC,GAAW;AAAA,IAC5C,UAAU,CAAcC,gBAAAA,EAAKC,GAAM;AAAA,MACjC,MAAMJ;AAAA,MACN,4BAA4B,QAAQ;AAAA,QAClC,WAAWN,EAAO;AAAA,QAClB,UAAUM;AAAA,MAAA,CACX;AAAA,IAAA,CACF,GAAgBG,gBAAAA,EAAKE,GAAM;AAAA,MAC1B,SAAS;AAAA,MACT,WAAWX,EAAO;AAAA,MAClB,UAAAN;AAAA,IAAA,CACD,CAAC;AAAA,EAAA,CACH;AACD,2BAA0B,OAAO;AAAA,IAC/B,WAAWK,EAAGC,EAAO,QAAQL,CAAS;AAAA,IACtC,kBAAkBU,IAAU,KAAO;AAAA,IACnC,GAAGP;AAAA,IACH,UAAU,CAAcW,gBAAAA,EAAKC,GAAM;AAAA,MACjC,MAAML;AAAA,MACN,UAAUE;AAAA,MACV,UAAU,CAAAK,MAAsBH,gBAAAA,EAAKI,GAAW;AAAA,QAC9C,SAASD;AAAA,QACT,4BAA4B,QAAQ;AAAA,UAClC,MAAM;AAAA,UACN,UAAU;AAAA,UACV,WAAWZ,EAAO;AAAA,UAClB,UAAUO;AAAA,QAAA,CACX;AAAA,MAAA,CACF;AAAA,IAAA,CACF,GAAgBE,gBAAAA,EAAKK,GAAQ;AAAA,MAC5B,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAOV;AAAA,MACP,WAAWJ,EAAO;AAAA,MAClB,YAAY,CAACG;AAAA,MACb,SAASA;AAAA,MACT,UAAUD;AAAA,IAAA,CACX,CAAC;AAAA,EAAA,CACH;AACH;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer components{.ComposerBanner_root_HyjFf2{display:flex;flex-direction:column;margin:0 var(--spacing-md);border-top-right-radius:calc(var(--radius-md) * var(--squircle-radius-factor));border-top-left-radius:calc(var(--radius-md) * var(--squircle-radius-factor));min-width:0;corner-shape:superellipse(var(--squircle-value)) superellipse(var(--squircle-value)) square square;background-color:var(--color-secondary-muted-light);overflow:hidden}.dark .ComposerBanner_root_HyjFf2:not([data-color]){background-color:var(--color-light-700)}.ComposerBanner_root_HyjFf2[data-color=danger]{background-color:var(--color-danger-muted-light);color:var(--color-danger-text)}.ComposerBanner_status_EIdxnS+.ComposerBanner_status_EIdxnS{position:relative}.ComposerBanner_status_EIdxnS+.ComposerBanner_status_EIdxnS:before{position:absolute;top:0;right:var(--spacing-sm);left:var(--spacing-sm);border-top:1px solid var(--color-secondary-muted-border);content:""}.ComposerBanner_root_HyjFf2[data-color=danger] .ComposerBanner_status_EIdxnS+.ComposerBanner_status_EIdxnS:before{border-top-color:var(--color-danger-muted-border)}.ComposerBanner_status_EIdxnS{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-sm);padding:var(--spacing-sm) var(--spacing-sm) var(--spacing-sm) var(--spacing-lg);word-wrap:break-word}.ComposerBanner_icon_5Md4lZ{display:flex;flex-shrink:0;color:var(--color-secondary-muted-text)}.ComposerBanner_text_UFktfG{flex:1;max-height:3lh;overflow:hidden}}
|
|
1
|
+
@layer components{.ComposerBanner_root_HyjFf2{display:flex;flex-direction:column;margin:0 var(--spacing-md);border-top-right-radius:calc(var(--radius-md) * var(--squircle-radius-factor));border-top-left-radius:calc(var(--radius-md) * var(--squircle-radius-factor));min-width:0;corner-shape:superellipse(var(--squircle-value)) superellipse(var(--squircle-value)) square square;background-color:var(--color-secondary-muted-light);overflow:hidden}.dark .ComposerBanner_root_HyjFf2:not([data-color]){background-color:var(--color-light-700)}.ComposerBanner_root_HyjFf2[data-color=danger]{background-color:var(--color-danger-muted-light);color:var(--color-danger-text)}.ComposerBanner_status_EIdxnS+.ComposerBanner_status_EIdxnS{position:relative}.ComposerBanner_status_EIdxnS+.ComposerBanner_status_EIdxnS:before{position:absolute;top:0;right:var(--spacing-sm);left:var(--spacing-sm);border-top:1px solid var(--color-secondary-muted-border);content:""}.ComposerBanner_root_HyjFf2[data-color=danger] .ComposerBanner_status_EIdxnS+.ComposerBanner_status_EIdxnS:before{border-top-color:var(--color-danger-muted-border)}.ComposerBanner_status_EIdxnS{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-sm);padding:var(--spacing-sm) var(--spacing-sm) var(--spacing-sm) var(--spacing-lg);word-wrap:break-word}.ComposerBanner_icon_5Md4lZ{display:flex;flex-shrink:0;color:var(--color-secondary-muted-text)}.ComposerBanner_text_UFktfG{flex:1;max-height:3lh;overflow:hidden}.ComposerBanner_status_EIdxnS[data-pressable]{position:relative}.ComposerBanner_press_FFVYdF{display:flex;flex:1;align-items:center;gap:var(--spacing-sm);cursor:pointer;outline:none;min-width:0}.ComposerBanner_press_FFVYdF:after{position:absolute;inset:0;content:""}.ComposerBanner_press_FFVYdF:focus-visible:after{outline:var(--spacing-4) solid var(--color-primary-muted-border);outline-offset:calc(var(--spacing-4) * -1)}.ComposerBanner_status_EIdxnS[data-pressable]:hover{background-color:var(--color-secondary-muted)}.ComposerBanner_action_EUqshm{position:relative}}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
const
|
|
2
|
-
root:
|
|
3
|
-
status:
|
|
4
|
-
icon:
|
|
5
|
-
text: n
|
|
1
|
+
const o = "ComposerBanner_root_HyjFf2", s = "ComposerBanner_status_EIdxnS", t = "ComposerBanner_icon_5Md4lZ", n = "ComposerBanner_text_UFktfG", e = "ComposerBanner_press_FFVYdF", r = "ComposerBanner_action_EUqshm", a = {
|
|
2
|
+
root: o,
|
|
3
|
+
status: s,
|
|
4
|
+
icon: t,
|
|
5
|
+
text: n,
|
|
6
|
+
press: e,
|
|
7
|
+
action: r
|
|
6
8
|
};
|
|
7
9
|
export {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
t as
|
|
11
|
-
|
|
10
|
+
r as action,
|
|
11
|
+
a as default,
|
|
12
|
+
t as icon,
|
|
13
|
+
e as press,
|
|
14
|
+
o as root,
|
|
15
|
+
s as status,
|
|
12
16
|
n as text
|
|
13
17
|
};
|
|
14
18
|
//# sourceMappingURL=ComposerBanner.module.css.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComposerBanner.module.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ComposerBanner.module.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationPendingLoader.d.ts","sourceRoot":"","sources":["../../../src/chat/Conversation/ConversationPendingLoader.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ConversationPendingLoader.d.ts","sourceRoot":"","sources":["../../../src/chat/Conversation/ConversationPendingLoader.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,MAAM,MAAM,8BAA8B,GAAG;IACzC,sFAAsF;IACtF,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,sGAAsG;IACtG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACxC,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,oFAAoF;AACpF,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAmBnF;AAkDD,qEAAqE;AACrE,wBAAgB,yBAAyB,CAAC,EACtC,QAAQ,EACR,SAAS,EACT,KAAK,EACL,KAAK,EACL,IAAY,EACZ,SAAS,GACZ,EAAE,8BAA8B,sCAsChC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ProgressLoader as h } from "@reforma/icons/assets";
|
|
2
2
|
import { cn as p } from "@reforma/lib";
|
|
3
|
-
import { isReasoningUIPart as g, isTextUIPart as P, isToolUIPart as w } from "
|
|
3
|
+
import { isReasoningUIPart as g, isTextUIPart as P, isToolUIPart as w } from "@reforma/types";
|
|
4
4
|
import { useSyncExternalStore as v, useEffect as L } from "react";
|
|
5
5
|
import { Shimmer as S } from "../../Shimmer/Shimmer.js";
|
|
6
6
|
import { Show as T } from "../../Show/Show.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationPendingLoader.js","sources":["../../../src/chat/Conversation/ConversationPendingLoader.tsx"],"sourcesContent":["'use client';\n\nimport { ProgressLoader } from '@reforma/icons/assets';\nimport { cn } from '@reforma/lib';\nimport {
|
|
1
|
+
{"version":3,"file":"ConversationPendingLoader.js","sources":["../../../src/chat/Conversation/ConversationPendingLoader.tsx"],"sourcesContent":["'use client';\n\nimport { ProgressLoader } from '@reforma/icons/assets';\nimport { cn } from '@reforma/lib';\nimport { isReasoningUIPart, isTextUIPart, isToolUIPart } from '@reforma/types';\nimport { useEffect, useSyncExternalStore } from 'react';\n\nimport { Shimmer } from '../../Shimmer';\nimport { Show } from '../../Show';\nimport { Text } from '../../Text/Text';\nimport { isContextCompactionUIPart } from '../Message/parts/contextCompactionPart';\nimport { isToolInvocationInProgress } from '../Tool/helpers';\nimport { ToolShell, ToolShellHeader } from '../Tool/shell';\nimport styles from './ConversationPendingLoader.module.css';\nimport {\n appearPendingLoaderPhrase,\n getPendingLoaderPhraseSnapshot,\n hidePendingLoaderPhrase,\n msUntilPendingLoaderLongUpgrade,\n pendingLoaderScope,\n subscribePendingLoaderPhrase,\n upgradePendingLoaderPhrase,\n} from './pendingLoaderPhrase';\n\nimport type { ReformaUIMessagePart } from '../Message/types';\n\nexport type ConversationPendingLoaderProps = {\n /** Live assistant tail while streaming; omit for the pre-response submitted state. */\n lastPart?: ReformaUIMessagePart;\n /** Assistant message the wait belongs to. With `parts`, scopes the phrase to the current LLM step. */\n messageId?: string;\n /** Raw assistant parts, including invisible `step-start`. */\n parts?: readonly ReformaUIMessagePart[];\n /** Fixed shimmer label. Omit to rotate short / long pending phrases. */\n label?: string;\n /** Text-only shimmer (compact activity card). */\n bare?: boolean;\n className?: string;\n};\n\n/** True when the part already shows live UI, so the pending shimmer should hide. */\nexport function messagePartShowsPendingActivity(part: ReformaUIMessagePart): boolean {\n if (isContextCompactionUIPart(part)) {\n return !part.data.done;\n }\n\n // Streaming reasoning always shows chrome (\"Thinking...\" or a title), even with no body yet.\n if (isReasoningUIPart(part)) {\n return part.state !== 'done';\n }\n\n if (isTextUIPart(part)) {\n return part.state !== 'done' && part.text.trim().length > 0;\n }\n\n if (isToolUIPart(part)) {\n return isToolInvocationInProgress(part.state);\n }\n\n return false;\n}\n\nfunction usePendingLoaderPhrase(\n visible: boolean,\n label: string | undefined,\n messageId: string | undefined,\n parts: readonly ReformaUIMessagePart[] | undefined\n): string {\n const phrase = useSyncExternalStore(\n subscribePendingLoaderPhrase,\n getPendingLoaderPhraseSnapshot,\n getPendingLoaderPhraseSnapshot\n );\n const scope = parts ? pendingLoaderScope(messageId, parts) : undefined;\n const stepKey = scope?.stepKey;\n const progressKey = scope?.progressKey;\n\n useEffect(() => {\n if (label !== undefined || !visible) {\n return;\n }\n\n appearPendingLoaderPhrase(\n Date.now(),\n stepKey !== undefined && progressKey !== undefined\n ? { stepKey, progressKey }\n : undefined\n );\n\n const wait = msUntilPendingLoaderLongUpgrade(Date.now());\n\n if (wait === null) {\n return () => {\n hidePendingLoaderPhrase(Date.now());\n };\n }\n\n const timer = window.setTimeout(() => {\n upgradePendingLoaderPhrase(Date.now());\n }, wait);\n\n return () => {\n window.clearTimeout(timer);\n hidePendingLoaderPhrase(Date.now());\n };\n }, [label, progressKey, stepKey, visible]);\n\n return label ?? phrase;\n}\n\n/** Pending indicator at the bottom of a live conversation thread. */\nexport function ConversationPendingLoader({\n lastPart,\n messageId,\n parts,\n label,\n bare = false,\n className,\n}: ConversationPendingLoaderProps) {\n const visible = !(lastPart && messagePartShowsPendingActivity(lastPart));\n const phrase = usePendingLoaderPhrase(visible, label, messageId, parts);\n const shown = visible && Boolean(phrase);\n\n if (bare) {\n return (\n <Text\n className={ cn(styles.root, className) }\n data-hidden={ shown ? undefined : true }\n role=\"status\"\n aria-hidden={ shown ? undefined : true }\n aria-label={ shown ? phrase : undefined }\n >\n <Show when={ phrase }>\n { text => (\n <span className={ styles.phrase } key={ text }>\n <Shimmer duration={ 1 }>{text}</Shimmer>\n </span>\n ) }\n </Show>\n </Text>\n );\n }\n\n if (!shown) {\n return null;\n }\n\n return (\n <ToolShell className={ className } role=\"status\" aria-label={ phrase }>\n <ToolShellHeader\n state=\"input-streaming\"\n title={ phrase }\n icon={ <ProgressLoader size={ 14 } aria-hidden /> }\n />\n </ToolShell>\n );\n}\n"],"names":["messagePartShowsPendingActivity","part","isContextCompactionUIPart","isReasoningUIPart","isTextUIPart","isToolUIPart","isToolInvocationInProgress","usePendingLoaderPhrase","visible","label","messageId","parts","phrase","useSyncExternalStore","subscribePendingLoaderPhrase","getPendingLoaderPhraseSnapshot","scope","pendingLoaderScope","stepKey","progressKey","useEffect","appearPendingLoaderPhrase","wait","msUntilPendingLoaderLongUpgrade","hidePendingLoaderPhrase","timer","upgradePendingLoaderPhrase","ConversationPendingLoader","lastPart","bare","className","shown","Text","cn","styles","Show","text","_jsx","Shimmer","ToolShell","ToolShellHeader","ProgressLoader"],"mappings":";;;;;;;;;;;;;AAgBO,SAASA,EAAgCC,GAAM;AACpD,SAAIC,EAA0BD,CAAI,IACzB,CAACA,EAAK,KAAK,OAIhBE,EAAkBF,CAAI,IACjBA,EAAK,UAAU,SAEpBG,EAAaH,CAAI,IACZA,EAAK,UAAU,UAAUA,EAAK,KAAK,KAAA,EAAO,SAAS,IAExDI,EAAaJ,CAAI,IACZK,EAA2BL,EAAK,KAAK,IAEvC;AACT;AACA,SAASM,EAAuBC,GAASC,GAAOC,GAAWC,GAAO;AAChE,QAAMC,IAASC,EAAqBC,GAA8BC,GAAgCA,CAA8B,GAC1HC,IAAQL,IAAQM,EAAmBP,GAAWC,CAAK,IAAI,QACvDO,IAAUF,GAAO,SACjBG,IAAcH,GAAO;AAC3B,SAAAI,EAAU,MAAM;AACd,QAAIX,MAAU,UAAa,CAACD;AAC1B;AAEF,IAAAa,EAA0B,KAAK,IAAA,GAAOH,MAAY,UAAaC,MAAgB,SAAY;AAAA,MACzF,SAAAD;AAAA,MACA,aAAAC;AAAA,IAAA,IACE,MAAS;AACb,UAAMG,IAAOC,EAAgC,KAAK,IAAA,CAAK;AACvD,QAAID,MAAS;AACX,aAAO,MAAM;AACX,QAAAE,EAAwB,KAAK,KAAK;AAAA,MACpC;AAEF,UAAMC,IAAQ,OAAO,WAAW,MAAM;AACpC,MAAAC,EAA2B,KAAK,KAAK;AAAA,IACvC,GAAGJ,CAAI;AACP,WAAO,MAAM;AACX,aAAO,aAAaG,CAAK,GACzBD,EAAwB,KAAK,KAAK;AAAA,IACpC;AAAA,EACF,GAAG,CAACf,GAAOU,GAAaD,GAASV,CAAO,CAAC,GAClCC,KAASG;AAClB;AAGO,SAASe,EAA0B;AAAA,EACxC,UAAAC;AAAA,EACA,WAAAlB;AAAA,EACA,OAAAC;AAAA,EACA,OAAAF;AAAA,EACA,MAAAoB,IAAO;AAAA,EACP,WAAAC;AACF,GAAG;AACD,QAAMtB,IAAU,EAAEoB,KAAY5B,EAAgC4B,CAAQ,IAChEhB,IAASL,EAAuBC,GAASC,GAAOC,GAAWC,CAAK,GAChEoB,IAAQvB,KAAW,EAAQI;AACjC,SAAIiB,sBACuBG,GAAM;AAAA,IAC7B,WAAWC,EAAGC,EAAO,MAAMJ,CAAS;AAAA,IACpC,eAAeC,IAAQ,SAAY;AAAA,IACnC,MAAM;AAAA,IACN,eAAeA,IAAQ,SAAY;AAAA,IACnC,cAAcA,IAAQnB,IAAS;AAAA,IAC/B,4BAA4BuB,GAAM;AAAA,MAChC,MAAMvB;AAAA,MACN,UAAU,CAAAwB,MAAqBC,gBAAAA,EAAK,QAAQ;AAAA,QAC1C,WAAWH,EAAO;AAAA,QAClB,4BAA4BI,GAAS;AAAA,UACnC,UAAU;AAAA,UACV,UAAUF;AAAA,QAAA,CACX;AAAA,MAAA,GACAA,CAAI;AAAA,IAAA,CACR;AAAA,EAAA,CACF,IAEEL,sBAGoBQ,GAAW;AAAA,IAClC,WAAAT;AAAA,IACA,MAAM;AAAA,IACN,cAAclB;AAAA,IACd,4BAA4B4B,GAAiB;AAAA,MAC3C,OAAO;AAAA,MACP,OAAO5B;AAAA,MACP,wBAAwB6B,GAAgB;AAAA,QACtC,MAAM;AAAA,QACN,eAAe;AAAA,MAAA,CAChB;AAAA,IAAA,CACF;AAAA,EAAA,CACF,IAdQ;AAeX;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type FileUIPart, type ReasoningUIPart, type SourceDocumentUIPart, type SourceUrlUIPart, type ToolUIPart } from 'ai';
|
|
2
1
|
import { type ContextCompactionUIPart } from '../parts/contextCompactionPart';
|
|
2
|
+
import type { FileUIPart, ReasoningUIPart, SourceDocumentUIPart, SourceUrlUIPart, ToolUIPart } from 'ai';
|
|
3
3
|
import type { ReformaUIMessagePart } from '../types';
|
|
4
4
|
export type MessageSegmentLayout = 'grouped' | 'ungrouped';
|
|
5
5
|
/** Step markers and UI-less tools — dropped before normalization. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalizeMessageParts.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/normalize/normalizeMessageParts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"normalizeMessageParts.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/normalize/normalizeMessageParts.ts"],"names":[],"mappings":"AAcA,OAAO,EAA6B,KAAK,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAGzG,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,oBAAoB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACzG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAErD,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,WAAW,CAAC;AAE3D,qEAAqE;AACrE,eAAO,MAAM,oBAAoB,aAY/B,CAAC;AAEH,oFAAoF;AACpF,MAAM,MAAM,gBAAgB,GACpB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,uBAAuB,EAAE,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,eAAe,EAAE,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG;IACzB,MAAM,EAAE,oBAAoB,CAAC;IAC7B,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACpC,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,kGAAkG;AAClG,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,oBAAoB,EAAE,CAElG;AAwBD;;GAEG;AACH,wBAAgB,8BAA8B,CAC1C,KAAK,EAAE,SAAS,oBAAoB,EAAE,GACvC,UAAU,GAAG,SAAS,CAcxB;AAQD;;GAEG;AACH,wBAAgB,oCAAoC,CAChD,KAAK,EAAE,SAAS,oBAAoB,EAAE,GACvC,UAAU,GAAG,SAAS,CAcxB;AAuBD,gGAAgG;AAChG,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG,OAAO,CAEtF;AAED,0FAA0F;AAC1F,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG,OAAO,CAQtF;AAED,wFAAwF;AACxF,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,OAAO,CAEtF;AAaD,wBAAgB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CA0CjE;AA2DD,qEAAqE;AACrE,wBAAgB,yBAAyB,CACrC,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,WAAW,EAAE,OAAO,GACrB,MAAM,CAgBR;AAwCD,2FAA2F;AAC3F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG,gBAAgB,EAAE,CAmB5F;AAED,0DAA0D;AAC1D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG;IAC3E,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CAChB,CAcA;AAED,wCAAwC;AACxC,wBAAgB,yBAAyB,CACrC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GACpC,oBAAoB,GAAG,SAAS,CAQlC;AAoCD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,cAAc,EAAE,CA8CpF;AA2BD,uGAAuG;AACvG,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAuCnG"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isStaticToolUIPart as s, getToolName as l, isDataUIPart as b, isTextUIPart as a, isReasoningUIPart as d, isToolUIPart as f, isFileUIPart as T } from "
|
|
1
|
+
import { isStaticToolUIPart as s, getToolName as l, isDataUIPart as b, isTextUIPart as a, isReasoningUIPart as d, isToolUIPart as f, isFileUIPart as T } from "@reforma/types";
|
|
2
2
|
import { parseReasoningText as A } from "../../Reasoning/normalizeReasoningBody.js";
|
|
3
3
|
import { isToolInvocationTerminal as P } from "../../Tool/helpers.js";
|
|
4
4
|
import { parseCallDynamicToolInput as M } from "../../Tool/mcp-tools/parseCallDynamicToolInput.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalizeMessageParts.js","sources":["../../../../src/chat/Message/normalize/normalizeMessageParts.ts"],"sourcesContent":["import {\n getToolName,\n isDataUIPart,\n isFileUIPart,\n isReasoningUIPart,\n isStaticToolUIPart,\n isTextUIPart,\n isToolUIPart,\n type FileUIPart,\n type ReasoningUIPart,\n type SourceDocumentUIPart,\n type SourceUrlUIPart,\n type ToolUIPart,\n} from 'ai';\n\nimport { parseReasoningText } from '../../Reasoning/normalizeReasoningBody';\nimport { isToolInvocationTerminal } from '../../Tool/helpers';\nimport { parseCallDynamicToolInput } from '../../Tool/mcp-tools/parseCallDynamicToolInput';\nimport { isBackgroundResultUIPart } from '../parts/backgroundResultPart';\nimport { isContextCompactionUIPart, type ContextCompactionUIPart } from '../parts/contextCompactionPart';\nimport { isRedactedReasoningUIPart } from '../parts/redactedReasoningPart';\n\nimport type { ReformaUIMessagePart } from '../types';\n\nexport type MessageSegmentLayout = 'grouped' | 'ungrouped';\n\n/** Step markers and UI-less tools — dropped before normalization. */\nexport const INVISIBLE_PART_TYPES = new Set([\n 'step-start',\n 'tool-SetPhase',\n 'tool-TodoWrite',\n 'tool-ReadTodo',\n 'tool-Commit',\n // Frontend tools without chat UI — executed silently in the editor.\n 'tool-Navigate',\n // Direction phase exit. The reading stays on the thread for the model.\n 'tool-CommitDesignRead',\n // Reveals the preview. The status change is the UI; the thread stays quiet.\n 'tool-MarkProjectReady',\n]);\n\n/** Render unit: merged file/source/compaction siblings, or one SDK part per row. */\nexport type MessagePartGroup\n = | { kind: 'files'; parts: FileUIPart[] }\n | { kind: 'sources'; parts: (SourceUrlUIPart | SourceDocumentUIPart)[] }\n | { kind: 'compaction'; parts: ContextCompactionUIPart[] }\n | { kind: 'reasoning'; parts: ReasoningUIPart[] }\n | { kind: 'single'; part: ReformaUIMessagePart };\n\nexport type MessageSegment = {\n layout: MessageSegmentLayout;\n groups: readonly MessagePartGroup[];\n /** Start index in the grouped sequence (keys / DOM id prefixes). */\n index: number;\n};\n\n/** Single tool/text rows from a segment's groups (skips merged file/source/compaction groups). */\nexport function partsFromSegmentGroups(groups: readonly MessagePartGroup[]): ReformaUIMessagePart[] {\n return groups.flatMap(group => group.kind === 'single' ? [group.part] : []);\n}\n\nfunction partRequiresUserAction(part: ReformaUIMessagePart): boolean {\n if (!isStaticToolUIPart(part)) {\n return false;\n }\n\n // Answered Ask / design picker folds into the work phase; pending stays outside.\n const name = getToolName(part);\n\n return part.state === 'approval-requested'\n || (\n (name === 'AskUserQuestion' || name === 'ChooseDesignDirection')\n && part.state !== 'output-available'\n );\n}\n\n/** Pending AskUserQuestion — answered in the composer; thread shows a pointer row. */\nfunction isPendingAskUserQuestionPart(part: ReformaUIMessagePart): boolean {\n return isStaticToolUIPart(part)\n && getToolName(part) === 'AskUserQuestion'\n && (part.state === 'input-streaming' || part.state === 'input-available');\n}\n\n/**\n * Last unfinished tool on the assistant turn, when that tool is a pending AskUserQuestion.\n */\nexport function lastPendingAskUserQuestionPart(\n parts: readonly ReformaUIMessagePart[]\n): ToolUIPart | undefined {\n const part = parts.findLast((entry) => {\n if (!isToolUIPart(entry)) {\n return false;\n }\n\n return !isToolInvocationTerminal(entry.state);\n });\n\n if (!part || !isToolUIPart(part) || !isPendingAskUserQuestionPart(part)) {\n return undefined;\n }\n\n return part as ToolUIPart;\n}\n\nfunction isPendingChooseDesignDirectionPart(part: ReformaUIMessagePart): boolean {\n return isStaticToolUIPart(part)\n && getToolName(part) === 'ChooseDesignDirection'\n && (part.state === 'input-streaming' || part.state === 'input-available');\n}\n\n/**\n * Last unfinished tool on the assistant turn, when that tool is a pending ChooseDesignDirection.\n */\nexport function lastPendingChooseDesignDirectionPart(\n parts: readonly ReformaUIMessagePart[]\n): ToolUIPart | undefined {\n const part = parts.findLast((entry) => {\n if (!isToolUIPart(entry)) {\n return false;\n }\n\n return !isToolInvocationTerminal(entry.state);\n });\n\n if (!part || !isToolUIPart(part) || !isPendingChooseDesignDirectionPart(part)) {\n return undefined;\n }\n\n return part as ToolUIPart;\n}\n\n/** Tools that never join Explored/Edited/Setup chrome. */\nconst OUTSIDE_PHASE_TOOLS = new Set([\n 'Preamble',\n 'ReadPlan',\n 'CreatePlan',\n 'EditPlan',\n]);\n\n/** Pending ask/approval, Preamble, and plan cards. */\nfunction toolStaysOutsidePhase(part: ReformaUIMessagePart): boolean {\n if (partRequiresUserAction(part)) {\n return true;\n }\n\n if (!isStaticToolUIPart(part)) {\n return false;\n }\n\n return OUTSIDE_PHASE_TOOLS.has(getToolName(part));\n}\n\n/** True when any tool call is still open (including invisible frontend tools like Navigate). */\nexport function partsHaveOpenToolCalls(parts: readonly ReformaUIMessagePart[]): boolean {\n return parts.some(part => isToolUIPart(part) && !isToolInvocationTerminal(part.state));\n}\n\n/** True when the turn awaits approval, a pending question, or a design-direction pick. */\nexport function partsRequireUserAction(parts: readonly ReformaUIMessagePart[]): boolean {\n if (lastPendingAskUserQuestionPart(parts) || lastPendingChooseDesignDirectionPart(parts)) {\n return true;\n }\n\n const tail = parts.findLast(isVisiblePart);\n\n return tail ? partRequiresUserAction(tail) : false;\n}\n\n/** True when a grouped segment contains a tool awaiting user confirmation or answer. */\nexport function segmentRequiresUserAction(groups: readonly MessagePartGroup[]): boolean {\n return groups.some(group => group.kind === 'single' && partRequiresUserAction(group.part));\n}\n\n/** Gateway call whose inner tool has no chat row (Navigate, and the other silent tools). */\nfunction isInvisibleDynamicTool(part: ReformaUIMessagePart): boolean {\n if (!isStaticToolUIPart(part) || getToolName(part) !== 'CallDynamicTool') {\n return false;\n }\n\n const { toolName } = parseCallDynamicToolInput(part.input);\n\n return INVISIBLE_PART_TYPES.has(`tool-${ toolName }`);\n}\n\nexport function isVisiblePart(part: ReformaUIMessagePart): boolean {\n if (INVISIBLE_PART_TYPES.has(part.type) || isInvisibleDynamicTool(part)) {\n return false;\n }\n\n // Login plaque only; after the user responds the part stays in the thread for the model.\n if (isStaticToolUIPart(part) && getToolName(part) === 'McpAuth') {\n return part.state === 'approval-requested';\n }\n\n // Citations render in the message footer, not the body.\n if (part.type === 'source-url' || part.type === 'source-document') {\n return false;\n }\n\n if (isContextCompactionUIPart(part) || isBackgroundResultUIPart(part)) {\n return true;\n }\n\n if (isDataUIPart(part)) {\n return false;\n }\n\n // Empty / whitespace-only text — no Streamdown shell (avoids empty prose gap before pending).\n if (isTextUIPart(part) && !part.text.trim()) {\n return false;\n }\n\n if (isReasoningUIPart(part) && part.state === 'done') {\n const { body } = parseReasoningText(part.text);\n\n // Drop settled reasoning with no body — including title-only `**Heading**`.\n if (!body.trim()) {\n return false;\n }\n }\n\n if (isRedactedReasoningUIPart(part)) {\n return false;\n }\n\n return true;\n}\n\nfunction isSourceUIPart(part: ReformaUIMessagePart): part is SourceUrlUIPart | SourceDocumentUIPart {\n return part.type === 'source-url' || part.type === 'source-document';\n}\n\nfunction isReasoningGroup(group: MessagePartGroup): boolean {\n return group.kind === 'reasoning';\n}\n\n/** Text, Preamble, pending ask/approval, plan cards, files, or trailing compaction. */\nfunction isOutsideGroup(\n group: MessagePartGroup,\n groupIndex: number,\n groups: readonly MessagePartGroup[]\n): boolean {\n if (group.kind === 'files' || group.kind === 'sources') {\n return true;\n }\n\n if (group.kind === 'compaction') {\n return groupIndex === groups.length - 1;\n }\n\n if (group.kind !== 'single') {\n return false;\n }\n\n const { part } = group;\n\n return isTextUIPart(part) || toolStaysOutsidePhase(part);\n}\n\n/** Reasoning follows the next in-phase group. */\nfunction laterJoinsPhase(\n from: number,\n groups: readonly MessagePartGroup[]\n): boolean {\n for (let index = from + 1; index < groups.length; index++) {\n if (isReasoningGroup(groups[index])) {\n continue;\n }\n\n return !isOutsideGroup(groups[index], index, groups);\n }\n\n return false;\n}\n\n/** Text, Preamble, pending ask, plan, or files after a phase — ends streaming phase chrome. */\nfunction sealsStreamingPhase(group: MessagePartGroup): boolean {\n if (group.kind === 'files' || group.kind === 'sources' || group.kind === 'compaction') {\n return true;\n }\n\n return group.kind === 'single'\n && (isTextUIPart(group.part) || toolStaysOutsidePhase(group.part));\n}\n\n/** Last grouped phase that should keep streaming chrome, or `-1`. */\nexport function streamingPhaseActiveIndex(\n segments: readonly MessageSegment[],\n isStreaming: boolean\n): number {\n if (!isStreaming) {\n return -1;\n }\n\n const lastGrouped = segments.findLastIndex(segment => segment.layout === 'grouped');\n\n if (lastGrouped < 0) {\n return -1;\n }\n\n const sealed = segments\n .slice(lastGrouped + 1)\n .some(segment => segment.groups.some(sealsStreamingPhase));\n\n return sealed ? -1 : lastGrouped;\n}\n\ntype MergeableGroupKind = Exclude<MessagePartGroup['kind'], 'single'>;\n\nfunction mergeableGroupKind(part: ReformaUIMessagePart): MergeableGroupKind | null {\n if (isFileUIPart(part)) {\n return 'files';\n }\n\n if (isSourceUIPart(part)) {\n return 'sources';\n }\n\n if (isContextCompactionUIPart(part)) {\n return 'compaction';\n }\n\n if (isReasoningUIPart(part)) {\n return 'reasoning';\n }\n\n return null;\n}\n\nfunction appendToMergeableGroup(\n groups: MessagePartGroup[],\n kind: MergeableGroupKind,\n part: ReformaUIMessagePart\n): void {\n const last = groups.at(-1);\n\n if (last?.kind === kind) {\n last.parts.push(part as never);\n\n return;\n }\n\n groups.push({ kind, parts: [part] } as MessagePartGroup);\n}\n\n/** Filter invisible parts; merge consecutive files, sources, compaction, and reasoning. */\nexport function groupMessageParts(parts: readonly ReformaUIMessagePart[]): MessagePartGroup[] {\n const groups: MessagePartGroup[] = [];\n\n for (const part of parts) {\n if (!isVisiblePart(part)) {\n continue;\n }\n\n const kind = mergeableGroupKind(part);\n\n if (kind !== null) {\n appendToMergeableGroup(groups, kind, part);\n }\n else {\n groups.push({ kind: 'single', part });\n }\n }\n\n return groups;\n}\n\n/** User turns only carry file attachments and/or text. */\nexport function splitUserMessageParts(parts: readonly ReformaUIMessagePart[]): {\n files: FileUIPart[];\n text: string;\n} {\n const files: FileUIPart[] = [];\n const textChunks: string[] = [];\n\n for (const part of parts) {\n if (isFileUIPart(part)) {\n files.push(part);\n }\n else if (isTextUIPart(part) && part.text.trim()) {\n textChunks.push(part.text);\n }\n }\n\n return { files, text: textChunks.join('\\n') };\n}\n\n/** Last visible part in render order */\nexport function lastVisiblePartFromGroups(\n groups: readonly MessagePartGroup[]\n): ReformaUIMessagePart | undefined {\n const lastGroup = groups.at(-1);\n\n if (!lastGroup) {\n return undefined;\n }\n\n return lastGroup.kind === 'single' ? lastGroup.part : lastGroup.parts.at(-1);\n}\n\nfunction flushSegment(\n segments: MessageSegment[],\n layout: MessageSegmentLayout,\n slice: MessagePartGroup[],\n index: number\n): number {\n if (slice.length === 0) {\n return index;\n }\n\n const groups = slice.splice(0);\n\n segments.push({ layout, groups, index });\n\n return index + groups.length;\n}\n\nfunction phaseLayout(groups: readonly MessagePartGroup[]): MessageSegmentLayout {\n let tools = 0;\n\n for (const group of groups) {\n if (group.kind === 'single' && isToolUIPart(group.part)) {\n tools++;\n }\n }\n\n if (tools === 0) {\n return 'ungrouped';\n }\n\n // 2+ rows: two tools, or a tool plus reasoning.\n return groups.length >= 2 ? 'grouped' : 'ungrouped';\n}\n\n/**\n * One work phase vs ungrouped separators (text, Preamble, pending ask/approval, plan).\n * Answered Ask joins the phase.\n * `grouped` chrome when a phase has 2+ rows (tools and/or reasoning) and at least one tool.\n */\nexport function segmentMessage(groups: readonly MessagePartGroup[]): MessageSegment[] {\n if (groups.length === 0) {\n return [];\n }\n\n const segments: MessageSegment[] = [];\n let index = 0;\n const phaseRun: MessagePartGroup[] = [];\n const outsideRun: MessagePartGroup[] = [];\n\n const intoPhase = (group: MessagePartGroup) => {\n index = flushSegment(segments, 'ungrouped', outsideRun, index);\n phaseRun.push(group);\n };\n\n const outsidePhase = (group: MessagePartGroup) => {\n index = flushSegment(segments, phaseLayout(phaseRun), phaseRun, index);\n outsideRun.push(group);\n };\n\n for (const [groupIndex, group] of groups.entries()) {\n const phaseOpen = phaseRun.length > 0;\n\n if (isReasoningGroup(group)) {\n if (phaseOpen || laterJoinsPhase(groupIndex, groups)) {\n intoPhase(group);\n }\n else {\n outsidePhase(group);\n }\n\n continue;\n }\n\n if (isOutsideGroup(group, groupIndex, groups)) {\n outsidePhase(group);\n }\n else {\n intoPhase(group);\n }\n }\n\n index = flushSegment(segments, phaseLayout(phaseRun), phaseRun, index);\n flushSegment(segments, 'ungrouped', outsideRun, index);\n\n return segments;\n}\n\n/** Value equality: same reference first, then a cached JSON fingerprint for streaming inputs. */\nconst inputFingerprintCache = new WeakMap<object, string>();\n\nfunction streamingInputFingerprint(input: unknown): string {\n if (input === null || input === undefined) {\n return '';\n }\n\n if (typeof input !== 'object') {\n return `${ typeof input }:${ String(input) }`;\n }\n\n const cached = inputFingerprintCache.get(input);\n\n if (cached !== undefined) {\n return cached;\n }\n\n const fingerprint = JSON.stringify(input);\n\n inputFingerprintCache.set(input, fingerprint);\n\n return fingerprint;\n}\n\n/** Shallow part equality; text/reasoning also compare content (streaming may replace part objects). */\nexport function uiMessagePartEqual(left: ReformaUIMessagePart, right: ReformaUIMessagePart): boolean {\n if (left === right) {\n return true;\n }\n\n if (left.type !== right.type) {\n return false;\n }\n\n if (isTextUIPart(left) && isTextUIPart(right)) {\n return left.text === right.text;\n }\n\n if (isReasoningUIPart(left) && isReasoningUIPart(right)) {\n return left.text === right.text && left.state === right.state;\n }\n\n if (isContextCompactionUIPart(left) && isContextCompactionUIPart(right)) {\n return left.data.done === right.data.done;\n }\n\n if (isBackgroundResultUIPart(left) && isBackgroundResultUIPart(right)) {\n return left.data.text === right.data.text;\n }\n\n if (isStaticToolUIPart(left) && isStaticToolUIPart(right)) {\n if (left.toolCallId !== right.toolCallId || left.state !== right.state) {\n return false;\n }\n\n if (left.state === 'input-streaming') {\n return left.input === right.input\n || streamingInputFingerprint(left.input) === streamingInputFingerprint(right.input);\n }\n\n return true;\n }\n\n return false;\n}\n"],"names":["INVISIBLE_PART_TYPES","partsFromSegmentGroups","groups","group","partRequiresUserAction","part","isStaticToolUIPart","name","getToolName","isPendingAskUserQuestionPart","lastPendingAskUserQuestionPart","parts","entry","isToolUIPart","isToolInvocationTerminal","isPendingChooseDesignDirectionPart","lastPendingChooseDesignDirectionPart","OUTSIDE_PHASE_TOOLS","toolStaysOutsidePhase","partsHaveOpenToolCalls","partsRequireUserAction","tail","isVisiblePart","segmentRequiresUserAction","isInvisibleDynamicTool","toolName","parseCallDynamicToolInput","isContextCompactionUIPart","isBackgroundResultUIPart","isDataUIPart","isTextUIPart","isReasoningUIPart","body","parseReasoningText","isRedactedReasoningUIPart","isSourceUIPart","isReasoningGroup","isOutsideGroup","groupIndex","laterJoinsPhase","from","index","sealsStreamingPhase","streamingPhaseActiveIndex","segments","isStreaming","lastGrouped","segment","mergeableGroupKind","isFileUIPart","appendToMergeableGroup","kind","last","groupMessageParts","splitUserMessageParts","files","textChunks","lastVisiblePartFromGroups","lastGroup","flushSegment","layout","slice","phaseLayout","tools","segmentMessage","phaseRun","outsideRun","intoPhase","outsidePhase","phaseOpen","inputFingerprintCache","streamingInputFingerprint","input","cached","fingerprint","uiMessagePartEqual","left","right"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"normalizeMessageParts.js","sources":["../../../../src/chat/Message/normalize/normalizeMessageParts.ts"],"sourcesContent":["import {\n getToolName,\n isDataUIPart,\n isFileUIPart,\n isReasoningUIPart,\n isStaticToolUIPart,\n isTextUIPart,\n isToolUIPart,\n} from '@reforma/types';\n\nimport { parseReasoningText } from '../../Reasoning/normalizeReasoningBody';\nimport { isToolInvocationTerminal } from '../../Tool/helpers';\nimport { parseCallDynamicToolInput } from '../../Tool/mcp-tools/parseCallDynamicToolInput';\nimport { isBackgroundResultUIPart } from '../parts/backgroundResultPart';\nimport { isContextCompactionUIPart, type ContextCompactionUIPart } from '../parts/contextCompactionPart';\nimport { isRedactedReasoningUIPart } from '../parts/redactedReasoningPart';\n\nimport type { FileUIPart, ReasoningUIPart, SourceDocumentUIPart, SourceUrlUIPart, ToolUIPart } from 'ai';\nimport type { ReformaUIMessagePart } from '../types';\n\nexport type MessageSegmentLayout = 'grouped' | 'ungrouped';\n\n/** Step markers and UI-less tools — dropped before normalization. */\nexport const INVISIBLE_PART_TYPES = new Set([\n 'step-start',\n 'tool-SetPhase',\n 'tool-TodoWrite',\n 'tool-ReadTodo',\n 'tool-Commit',\n // Frontend tools without chat UI — executed silently in the editor.\n 'tool-Navigate',\n // Direction phase exit. The reading stays on the thread for the model.\n 'tool-CommitDesignRead',\n // Reveals the preview. The status change is the UI; the thread stays quiet.\n 'tool-MarkProjectReady',\n]);\n\n/** Render unit: merged file/source/compaction siblings, or one SDK part per row. */\nexport type MessagePartGroup\n = | { kind: 'files'; parts: FileUIPart[] }\n | { kind: 'sources'; parts: (SourceUrlUIPart | SourceDocumentUIPart)[] }\n | { kind: 'compaction'; parts: ContextCompactionUIPart[] }\n | { kind: 'reasoning'; parts: ReasoningUIPart[] }\n | { kind: 'single'; part: ReformaUIMessagePart };\n\nexport type MessageSegment = {\n layout: MessageSegmentLayout;\n groups: readonly MessagePartGroup[];\n /** Start index in the grouped sequence (keys / DOM id prefixes). */\n index: number;\n};\n\n/** Single tool/text rows from a segment's groups (skips merged file/source/compaction groups). */\nexport function partsFromSegmentGroups(groups: readonly MessagePartGroup[]): ReformaUIMessagePart[] {\n return groups.flatMap(group => group.kind === 'single' ? [group.part] : []);\n}\n\nfunction partRequiresUserAction(part: ReformaUIMessagePart): boolean {\n if (!isStaticToolUIPart(part)) {\n return false;\n }\n\n // Answered Ask / design picker folds into the work phase; pending stays outside.\n const name = getToolName(part);\n\n return part.state === 'approval-requested'\n || (\n (name === 'AskUserQuestion' || name === 'ChooseDesignDirection')\n && part.state !== 'output-available'\n );\n}\n\n/** Pending AskUserQuestion — answered in the composer; thread shows a pointer row. */\nfunction isPendingAskUserQuestionPart(part: ReformaUIMessagePart): boolean {\n return isStaticToolUIPart(part)\n && getToolName(part) === 'AskUserQuestion'\n && (part.state === 'input-streaming' || part.state === 'input-available');\n}\n\n/**\n * Last unfinished tool on the assistant turn, when that tool is a pending AskUserQuestion.\n */\nexport function lastPendingAskUserQuestionPart(\n parts: readonly ReformaUIMessagePart[]\n): ToolUIPart | undefined {\n const part = parts.findLast((entry) => {\n if (!isToolUIPart(entry)) {\n return false;\n }\n\n return !isToolInvocationTerminal(entry.state);\n });\n\n if (!part || !isToolUIPart(part) || !isPendingAskUserQuestionPart(part)) {\n return undefined;\n }\n\n return part as ToolUIPart;\n}\n\nfunction isPendingChooseDesignDirectionPart(part: ReformaUIMessagePart): boolean {\n return isStaticToolUIPart(part)\n && getToolName(part) === 'ChooseDesignDirection'\n && (part.state === 'input-streaming' || part.state === 'input-available');\n}\n\n/**\n * Last unfinished tool on the assistant turn, when that tool is a pending ChooseDesignDirection.\n */\nexport function lastPendingChooseDesignDirectionPart(\n parts: readonly ReformaUIMessagePart[]\n): ToolUIPart | undefined {\n const part = parts.findLast((entry) => {\n if (!isToolUIPart(entry)) {\n return false;\n }\n\n return !isToolInvocationTerminal(entry.state);\n });\n\n if (!part || !isToolUIPart(part) || !isPendingChooseDesignDirectionPart(part)) {\n return undefined;\n }\n\n return part as ToolUIPart;\n}\n\n/** Tools that never join Explored/Edited/Setup chrome. */\nconst OUTSIDE_PHASE_TOOLS = new Set([\n 'Preamble',\n 'ReadPlan',\n 'CreatePlan',\n 'EditPlan',\n]);\n\n/** Pending ask/approval, Preamble, and plan cards. */\nfunction toolStaysOutsidePhase(part: ReformaUIMessagePart): boolean {\n if (partRequiresUserAction(part)) {\n return true;\n }\n\n if (!isStaticToolUIPart(part)) {\n return false;\n }\n\n return OUTSIDE_PHASE_TOOLS.has(getToolName(part));\n}\n\n/** True when any tool call is still open (including invisible frontend tools like Navigate). */\nexport function partsHaveOpenToolCalls(parts: readonly ReformaUIMessagePart[]): boolean {\n return parts.some(part => isToolUIPart(part) && !isToolInvocationTerminal(part.state));\n}\n\n/** True when the turn awaits approval, a pending question, or a design-direction pick. */\nexport function partsRequireUserAction(parts: readonly ReformaUIMessagePart[]): boolean {\n if (lastPendingAskUserQuestionPart(parts) || lastPendingChooseDesignDirectionPart(parts)) {\n return true;\n }\n\n const tail = parts.findLast(isVisiblePart);\n\n return tail ? partRequiresUserAction(tail) : false;\n}\n\n/** True when a grouped segment contains a tool awaiting user confirmation or answer. */\nexport function segmentRequiresUserAction(groups: readonly MessagePartGroup[]): boolean {\n return groups.some(group => group.kind === 'single' && partRequiresUserAction(group.part));\n}\n\n/** Gateway call whose inner tool has no chat row (Navigate, and the other silent tools). */\nfunction isInvisibleDynamicTool(part: ReformaUIMessagePart): boolean {\n if (!isStaticToolUIPart(part) || getToolName(part) !== 'CallDynamicTool') {\n return false;\n }\n\n const { toolName } = parseCallDynamicToolInput(part.input);\n\n return INVISIBLE_PART_TYPES.has(`tool-${ toolName }`);\n}\n\nexport function isVisiblePart(part: ReformaUIMessagePart): boolean {\n if (INVISIBLE_PART_TYPES.has(part.type) || isInvisibleDynamicTool(part)) {\n return false;\n }\n\n // Login plaque only; after the user responds the part stays in the thread for the model.\n if (isStaticToolUIPart(part) && getToolName(part) === 'McpAuth') {\n return part.state === 'approval-requested';\n }\n\n // Citations render in the message footer, not the body.\n if (part.type === 'source-url' || part.type === 'source-document') {\n return false;\n }\n\n if (isContextCompactionUIPart(part) || isBackgroundResultUIPart(part)) {\n return true;\n }\n\n if (isDataUIPart(part)) {\n return false;\n }\n\n // Empty / whitespace-only text — no Streamdown shell (avoids empty prose gap before pending).\n if (isTextUIPart(part) && !part.text.trim()) {\n return false;\n }\n\n if (isReasoningUIPart(part) && part.state === 'done') {\n const { body } = parseReasoningText(part.text);\n\n // Drop settled reasoning with no body — including title-only `**Heading**`.\n if (!body.trim()) {\n return false;\n }\n }\n\n if (isRedactedReasoningUIPart(part)) {\n return false;\n }\n\n return true;\n}\n\nfunction isSourceUIPart(part: ReformaUIMessagePart): part is SourceUrlUIPart | SourceDocumentUIPart {\n return part.type === 'source-url' || part.type === 'source-document';\n}\n\nfunction isReasoningGroup(group: MessagePartGroup): boolean {\n return group.kind === 'reasoning';\n}\n\n/** Text, Preamble, pending ask/approval, plan cards, files, or trailing compaction. */\nfunction isOutsideGroup(\n group: MessagePartGroup,\n groupIndex: number,\n groups: readonly MessagePartGroup[]\n): boolean {\n if (group.kind === 'files' || group.kind === 'sources') {\n return true;\n }\n\n if (group.kind === 'compaction') {\n return groupIndex === groups.length - 1;\n }\n\n if (group.kind !== 'single') {\n return false;\n }\n\n const { part } = group;\n\n return isTextUIPart(part) || toolStaysOutsidePhase(part);\n}\n\n/** Reasoning follows the next in-phase group. */\nfunction laterJoinsPhase(\n from: number,\n groups: readonly MessagePartGroup[]\n): boolean {\n for (let index = from + 1; index < groups.length; index++) {\n if (isReasoningGroup(groups[index])) {\n continue;\n }\n\n return !isOutsideGroup(groups[index], index, groups);\n }\n\n return false;\n}\n\n/** Text, Preamble, pending ask, plan, or files after a phase — ends streaming phase chrome. */\nfunction sealsStreamingPhase(group: MessagePartGroup): boolean {\n if (group.kind === 'files' || group.kind === 'sources' || group.kind === 'compaction') {\n return true;\n }\n\n return group.kind === 'single'\n && (isTextUIPart(group.part) || toolStaysOutsidePhase(group.part));\n}\n\n/** Last grouped phase that should keep streaming chrome, or `-1`. */\nexport function streamingPhaseActiveIndex(\n segments: readonly MessageSegment[],\n isStreaming: boolean\n): number {\n if (!isStreaming) {\n return -1;\n }\n\n const lastGrouped = segments.findLastIndex(segment => segment.layout === 'grouped');\n\n if (lastGrouped < 0) {\n return -1;\n }\n\n const sealed = segments\n .slice(lastGrouped + 1)\n .some(segment => segment.groups.some(sealsStreamingPhase));\n\n return sealed ? -1 : lastGrouped;\n}\n\ntype MergeableGroupKind = Exclude<MessagePartGroup['kind'], 'single'>;\n\nfunction mergeableGroupKind(part: ReformaUIMessagePart): MergeableGroupKind | null {\n if (isFileUIPart(part)) {\n return 'files';\n }\n\n if (isSourceUIPart(part)) {\n return 'sources';\n }\n\n if (isContextCompactionUIPart(part)) {\n return 'compaction';\n }\n\n if (isReasoningUIPart(part)) {\n return 'reasoning';\n }\n\n return null;\n}\n\nfunction appendToMergeableGroup(\n groups: MessagePartGroup[],\n kind: MergeableGroupKind,\n part: ReformaUIMessagePart\n): void {\n const last = groups.at(-1);\n\n if (last?.kind === kind) {\n last.parts.push(part as never);\n\n return;\n }\n\n groups.push({ kind, parts: [part] } as MessagePartGroup);\n}\n\n/** Filter invisible parts; merge consecutive files, sources, compaction, and reasoning. */\nexport function groupMessageParts(parts: readonly ReformaUIMessagePart[]): MessagePartGroup[] {\n const groups: MessagePartGroup[] = [];\n\n for (const part of parts) {\n if (!isVisiblePart(part)) {\n continue;\n }\n\n const kind = mergeableGroupKind(part);\n\n if (kind !== null) {\n appendToMergeableGroup(groups, kind, part);\n }\n else {\n groups.push({ kind: 'single', part });\n }\n }\n\n return groups;\n}\n\n/** User turns only carry file attachments and/or text. */\nexport function splitUserMessageParts(parts: readonly ReformaUIMessagePart[]): {\n files: FileUIPart[];\n text: string;\n} {\n const files: FileUIPart[] = [];\n const textChunks: string[] = [];\n\n for (const part of parts) {\n if (isFileUIPart(part)) {\n files.push(part);\n }\n else if (isTextUIPart(part) && part.text.trim()) {\n textChunks.push(part.text);\n }\n }\n\n return { files, text: textChunks.join('\\n') };\n}\n\n/** Last visible part in render order */\nexport function lastVisiblePartFromGroups(\n groups: readonly MessagePartGroup[]\n): ReformaUIMessagePart | undefined {\n const lastGroup = groups.at(-1);\n\n if (!lastGroup) {\n return undefined;\n }\n\n return lastGroup.kind === 'single' ? lastGroup.part : lastGroup.parts.at(-1);\n}\n\nfunction flushSegment(\n segments: MessageSegment[],\n layout: MessageSegmentLayout,\n slice: MessagePartGroup[],\n index: number\n): number {\n if (slice.length === 0) {\n return index;\n }\n\n const groups = slice.splice(0);\n\n segments.push({ layout, groups, index });\n\n return index + groups.length;\n}\n\nfunction phaseLayout(groups: readonly MessagePartGroup[]): MessageSegmentLayout {\n let tools = 0;\n\n for (const group of groups) {\n if (group.kind === 'single' && isToolUIPart(group.part)) {\n tools++;\n }\n }\n\n if (tools === 0) {\n return 'ungrouped';\n }\n\n // 2+ rows: two tools, or a tool plus reasoning.\n return groups.length >= 2 ? 'grouped' : 'ungrouped';\n}\n\n/**\n * One work phase vs ungrouped separators (text, Preamble, pending ask/approval, plan).\n * Answered Ask joins the phase.\n * `grouped` chrome when a phase has 2+ rows (tools and/or reasoning) and at least one tool.\n */\nexport function segmentMessage(groups: readonly MessagePartGroup[]): MessageSegment[] {\n if (groups.length === 0) {\n return [];\n }\n\n const segments: MessageSegment[] = [];\n let index = 0;\n const phaseRun: MessagePartGroup[] = [];\n const outsideRun: MessagePartGroup[] = [];\n\n const intoPhase = (group: MessagePartGroup) => {\n index = flushSegment(segments, 'ungrouped', outsideRun, index);\n phaseRun.push(group);\n };\n\n const outsidePhase = (group: MessagePartGroup) => {\n index = flushSegment(segments, phaseLayout(phaseRun), phaseRun, index);\n outsideRun.push(group);\n };\n\n for (const [groupIndex, group] of groups.entries()) {\n const phaseOpen = phaseRun.length > 0;\n\n if (isReasoningGroup(group)) {\n if (phaseOpen || laterJoinsPhase(groupIndex, groups)) {\n intoPhase(group);\n }\n else {\n outsidePhase(group);\n }\n\n continue;\n }\n\n if (isOutsideGroup(group, groupIndex, groups)) {\n outsidePhase(group);\n }\n else {\n intoPhase(group);\n }\n }\n\n index = flushSegment(segments, phaseLayout(phaseRun), phaseRun, index);\n flushSegment(segments, 'ungrouped', outsideRun, index);\n\n return segments;\n}\n\n/** Value equality: same reference first, then a cached JSON fingerprint for streaming inputs. */\nconst inputFingerprintCache = new WeakMap<object, string>();\n\nfunction streamingInputFingerprint(input: unknown): string {\n if (input === null || input === undefined) {\n return '';\n }\n\n if (typeof input !== 'object') {\n return `${ typeof input }:${ String(input) }`;\n }\n\n const cached = inputFingerprintCache.get(input);\n\n if (cached !== undefined) {\n return cached;\n }\n\n const fingerprint = JSON.stringify(input);\n\n inputFingerprintCache.set(input, fingerprint);\n\n return fingerprint;\n}\n\n/** Shallow part equality; text/reasoning also compare content (streaming may replace part objects). */\nexport function uiMessagePartEqual(left: ReformaUIMessagePart, right: ReformaUIMessagePart): boolean {\n if (left === right) {\n return true;\n }\n\n if (left.type !== right.type) {\n return false;\n }\n\n if (isTextUIPart(left) && isTextUIPart(right)) {\n return left.text === right.text;\n }\n\n if (isReasoningUIPart(left) && isReasoningUIPart(right)) {\n return left.text === right.text && left.state === right.state;\n }\n\n if (isContextCompactionUIPart(left) && isContextCompactionUIPart(right)) {\n return left.data.done === right.data.done;\n }\n\n if (isBackgroundResultUIPart(left) && isBackgroundResultUIPart(right)) {\n return left.data.text === right.data.text;\n }\n\n if (isStaticToolUIPart(left) && isStaticToolUIPart(right)) {\n if (left.toolCallId !== right.toolCallId || left.state !== right.state) {\n return false;\n }\n\n if (left.state === 'input-streaming') {\n return left.input === right.input\n || streamingInputFingerprint(left.input) === streamingInputFingerprint(right.input);\n }\n\n return true;\n }\n\n return false;\n}\n"],"names":["INVISIBLE_PART_TYPES","partsFromSegmentGroups","groups","group","partRequiresUserAction","part","isStaticToolUIPart","name","getToolName","isPendingAskUserQuestionPart","lastPendingAskUserQuestionPart","parts","entry","isToolUIPart","isToolInvocationTerminal","isPendingChooseDesignDirectionPart","lastPendingChooseDesignDirectionPart","OUTSIDE_PHASE_TOOLS","toolStaysOutsidePhase","partsHaveOpenToolCalls","partsRequireUserAction","tail","isVisiblePart","segmentRequiresUserAction","isInvisibleDynamicTool","toolName","parseCallDynamicToolInput","isContextCompactionUIPart","isBackgroundResultUIPart","isDataUIPart","isTextUIPart","isReasoningUIPart","body","parseReasoningText","isRedactedReasoningUIPart","isSourceUIPart","isReasoningGroup","isOutsideGroup","groupIndex","laterJoinsPhase","from","index","sealsStreamingPhase","streamingPhaseActiveIndex","segments","isStreaming","lastGrouped","segment","mergeableGroupKind","isFileUIPart","appendToMergeableGroup","kind","last","groupMessageParts","splitUserMessageParts","files","textChunks","lastVisiblePartFromGroups","lastGroup","flushSegment","layout","slice","phaseLayout","tools","segmentMessage","phaseRun","outsideRun","intoPhase","outsidePhase","phaseOpen","inputFingerprintCache","streamingInputFingerprint","input","cached","fingerprint","uiMessagePartEqual","left","right"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessagePart.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/parts/MessagePart.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MessagePart.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/parts/MessagePart.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAErD,MAAM,MAAM,gBAAgB,GAAG;IAC3B,IAAI,EAAE,oBAAoB,CAAC;IAC3B,4FAA4F;IAC5F,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gEAAgE;IAChE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAiBF;;;GAGG;AACH,iBAAS,eAAe,CAAC,EACrB,IAAI,EACJ,OAAO,EACP,WAAW,EACX,aAAa,EAAE,cAAc,EAC7B,aAAa,GAChB,EAAE,gBAAgB,sCA+ClB;AAED,eAAO,MAAM,WAAW,6DAA+C,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isTextUIPart as o, isReasoningUIPart as m, isFileUIPart as l, isToolUIPart as u } from "
|
|
1
|
+
import { isTextUIPart as o, isReasoningUIPart as m, isFileUIPart as l, isToolUIPart as u } from "@reforma/types";
|
|
2
2
|
import { memo as n } from "react";
|
|
3
3
|
import { Tool as f } from "../../Tool/Tool.js";
|
|
4
4
|
import { GetBackgroundResultTool as g } from "../../Tool/get-background-result/GetBackgroundResultTool.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessagePart.js","sources":["../../../../src/chat/Message/parts/MessagePart.tsx"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"MessagePart.js","sources":["../../../../src/chat/Message/parts/MessagePart.tsx"],"sourcesContent":["import { isFileUIPart, isReasoningUIPart, isTextUIPart, isToolUIPart } from '@reforma/types';\nimport { memo } from 'react';\n\nimport { Tool } from '../../Tool';\nimport { GetBackgroundResultTool } from '../../Tool/get-background-result';\nimport { uiMessagePartEqual } from '../normalize/normalizeMessageParts';\nimport { MessageText } from '../streamdown/MessageText';\nimport { isBackgroundResultUIPart } from './backgroundResultPart';\nimport { MessageFileParts } from './MessageFileParts';\nimport { MessagePartFallback } from './MessagePartFallback';\nimport { MessageReasoningParts } from './MessageReasoningParts';\nimport { isRedactedReasoningUIPart } from './redactedReasoningPart';\n\nimport type { ReformaUIMessagePart } from '../types';\n\nexport type MessagePartProps = {\n part: ReformaUIMessagePart;\n /** Stable key for this part (e.g. `${message.id}-${index}`), used for file part DOM ids. */\n partKey: string;\n isStreaming?: boolean;\n /** Live assistant slot in the thread (memo while streaming). */\n isLiveMessage?: boolean;\n /** Last render row in the live message. */\n isMessageTail?: boolean;\n};\n\nfunction messagePartPropsEqual(prev: MessagePartProps, next: MessagePartProps): boolean {\n if (prev.partKey !== next.partKey\n || prev.isMessageTail !== next.isMessageTail\n || prev.isStreaming !== next.isStreaming\n || prev.isLiveMessage !== next.isLiveMessage) {\n return false;\n }\n\n if (next.isStreaming && next.isLiveMessage) {\n return uiMessagePartEqual(prev.part, next.part);\n }\n\n return prev.part === next.part;\n}\n\n/**\n * One assistant/system `Message` part (text, reasoning, or tool). Memoized so frozen\n * siblings skip rerender; the streaming tail uses semantic part equality.\n */\nfunction MessagePartView({\n part,\n partKey,\n isStreaming,\n isLiveMessage: _isLiveMessage,\n isMessageTail,\n}: MessagePartProps) {\n const streamText = Boolean(isStreaming && isMessageTail);\n\n if (isTextUIPart(part)) {\n return (\n <MessageText mode={ streamText ? 'streaming' : 'static' }>{ part.text }</MessageText>\n );\n }\n\n if (isReasoningUIPart(part)) {\n return (\n <MessageReasoningParts\n parts={ [part] }\n isStreaming={ Boolean(isStreaming) }\n />\n );\n }\n\n if (isFileUIPart(part)) {\n return (\n <MessageFileParts fileParts={ [part] } idPrefix={ partKey } />\n );\n }\n\n if (isBackgroundResultUIPart(part)) {\n return (\n <GetBackgroundResultTool\n part={ {\n type: 'tool-GetBackgroundResult',\n toolCallId: part.id ?? part.data.id,\n state: 'output-available',\n input: {},\n output: part.data.results,\n } }\n />\n );\n }\n\n if (isToolUIPart(part)) {\n return <Tool part={ part } />;\n }\n\n if (isRedactedReasoningUIPart(part)) {\n return null;\n }\n\n return <MessagePartFallback part={ part } />;\n}\n\nexport const MessagePart = memo(MessagePartView, messagePartPropsEqual);\n"],"names":["messagePartPropsEqual","prev","next","uiMessagePartEqual","MessagePartView","part","partKey","isStreaming","_isLiveMessage","isMessageTail","streamText","isTextUIPart","MessageText","isReasoningUIPart","MessageReasoningParts","isFileUIPart","MessageFileParts","isBackgroundResultUIPart","GetBackgroundResultTool","isToolUIPart","Tool","isRedactedReasoningUIPart","MessagePartFallback","MessagePart","memo"],"mappings":";;;;;;;;;;;;AAYA,SAASA,EAAsBC,GAAMC,GAAM;AACzC,SAAID,EAAK,YAAYC,EAAK,WAAWD,EAAK,kBAAkBC,EAAK,iBAAiBD,EAAK,gBAAgBC,EAAK,eAAeD,EAAK,kBAAkBC,EAAK,gBAC9I,KAELA,EAAK,eAAeA,EAAK,gBACpBC,EAAmBF,EAAK,MAAMC,EAAK,IAAI,IAEzCD,EAAK,SAASC,EAAK;AAC5B;AAMA,SAASE,EAAgB;AAAA,EACvB,MAAAC;AAAA,EACA,SAAAC;AAAA,EACA,aAAAC;AAAA,EACA,eAAeC;AAAA,EACf,eAAAC;AACF,GAAG;AACD,QAAMC,IAAa,GAAQH,KAAeE;AAC1C,SAAIE,EAAaN,CAAI,sBACMO,GAAa;AAAA,IACpC,MAAMF,IAAa,cAAc;AAAA,IACjC,UAAUL,EAAK;AAAA,EAAA,CAChB,IAECQ,EAAkBR,CAAI,sBACCS,GAAuB;AAAA,IAC9C,OAAO,CAACT,CAAI;AAAA,IACZ,aAAa,EAAQE;AAAA,EAAW,CACjC,IAECQ,EAAaV,CAAI,sBACMW,GAAkB;AAAA,IACzC,WAAW,CAACX,CAAI;AAAA,IAChB,UAAUC;AAAA,EAAA,CACX,IAECW,EAAyBZ,CAAI,sBACNa,GAAyB;AAAA,IAChD,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,YAAYb,EAAK,MAAMA,EAAK,KAAK;AAAA,MACjC,OAAO;AAAA,MACP,OAAO,CAAA;AAAA,MACP,QAAQA,EAAK,KAAK;AAAA,IAAA;AAAA,EACpB,CACD,IAECc,EAAad,CAAI,sBACMe,GAAM;AAAA,IAC7B,MAAAf;AAAA,EAAA,CACD,IAECgB,EAA0BhB,CAAI,IACzB,yBAEgBiB,GAAqB;AAAA,IAC5C,MAAAjB;AAAA,EAAA,CACD;AACH;AACO,MAAMkB,IAA2B,gBAAAC,EAAKpB,GAAiBJ,CAAqB;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backgroundResultPart.js","sources":["../../../../src/chat/Message/parts/backgroundResultPart.ts"],"sourcesContent":["import { isDataUIPart } from '
|
|
1
|
+
{"version":3,"file":"backgroundResultPart.js","sources":["../../../../src/chat/Message/parts/backgroundResultPart.ts"],"sourcesContent":["import { isDataUIPart } from '@reforma/types';\n\nimport type { BackgroundResultNoticeData } from '@reforma/types';\nimport type { ReformaUIMessagePart } from '../types';\n\nexport type BackgroundResultUIPart = {\n type: 'data-background-result';\n id?: string;\n data: BackgroundResultNoticeData;\n};\n\nexport function isBackgroundResultUIPart(\n part: ReformaUIMessagePart\n): part is BackgroundResultUIPart {\n return isDataUIPart(part) && part.type === 'data-background-result';\n}\n"],"names":["isBackgroundResultUIPart","part","isDataUIPart"],"mappings":";AACO,SAASA,EAAyBC,GAAM;AAC7C,SAAOC,EAAaD,CAAI,KAAKA,EAAK,SAAS;AAC7C;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { SourceDocumentUIPart, SourceUrlUIPart } from 'ai';
|
|
2
2
|
import type { ReformaUIMessagePart } from '../types';
|
|
3
3
|
export type MessageSourcePart = SourceUrlUIPart | SourceDocumentUIPart;
|
|
4
4
|
/** Unique source parts for the message footer (first occurrence wins). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collectMessageSources.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/parts/collectMessageSources.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"collectMessageSources.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/parts/collectMessageSources.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAChE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAErD,MAAM,MAAM,iBAAiB,GAAG,eAAe,GAAG,oBAAoB,CAAC;AAiBvE,0EAA0E;AAC1E,wBAAgB,qBAAqB,CACjC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GACvC,iBAAiB,EAAE,CA6BrB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isToolUIPart as s, getToolName as l } from "
|
|
1
|
+
import { isToolUIPart as s, getToolName as l } from "@reforma/types";
|
|
2
2
|
import { isWebSearchToolName as n, webSearchSourcesFromOutput as i } from "../../Tool/web-search/parseWebSearchTool.js";
|
|
3
3
|
function c(t, u, e) {
|
|
4
4
|
const o = e.type === "source-url" ? `url:${e.url}` : `doc:${e.sourceId}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collectMessageSources.js","sources":["../../../../src/chat/Message/parts/collectMessageSources.ts"],"sourcesContent":["import { getToolName, isToolUIPart
|
|
1
|
+
{"version":3,"file":"collectMessageSources.js","sources":["../../../../src/chat/Message/parts/collectMessageSources.ts"],"sourcesContent":["import { getToolName, isToolUIPart } from '@reforma/types';\n\nimport {\n isWebSearchToolName,\n webSearchSourcesFromOutput,\n} from '../../Tool/web-search/parseWebSearchTool';\n\nimport type { SourceDocumentUIPart, SourceUrlUIPart } from 'ai';\nimport type { ReformaUIMessagePart } from '../types';\n\nexport type MessageSourcePart = SourceUrlUIPart | SourceDocumentUIPart;\n\nfunction pushUnique(\n seen: Set<string>,\n out: MessageSourcePart[],\n part: MessageSourcePart\n): void {\n const key = part.type === 'source-url' ? `url:${ part.url }` : `doc:${ part.sourceId }`;\n\n if (seen.has(key)) {\n return;\n }\n\n seen.add(key);\n out.push(part);\n}\n\n/** Unique source parts for the message footer (first occurrence wins). */\nexport function collectMessageSources(\n parts: readonly ReformaUIMessagePart[]\n): MessageSourcePart[] {\n const seen = new Set<string>();\n const out: MessageSourcePart[] = [];\n\n for (const part of parts) {\n if (part.type === 'source-url' || part.type === 'source-document') {\n pushUnique(seen, out, part);\n\n continue;\n }\n\n // Provider WebSearch embeds `{ type: 'url', url }` in tool output — not top-level source-* parts.\n if (\n isToolUIPart(part)\n && part.state === 'output-available'\n && isWebSearchToolName(getToolName(part))\n ) {\n for (const source of webSearchSourcesFromOutput(part.output)) {\n pushUnique(seen, out, {\n type: 'source-url',\n sourceId: source.url,\n url: source.url,\n title: source.title,\n });\n }\n }\n }\n\n return out;\n}\n"],"names":["pushUnique","seen","out","part","key","collectMessageSources","parts","isToolUIPart","isWebSearchToolName","getToolName","source","webSearchSourcesFromOutput"],"mappings":";;AAEA,SAASA,EAAWC,GAAMC,GAAKC,GAAM;AACnC,QAAMC,IAAMD,EAAK,SAAS,eAAe,OAAOA,EAAK,GAAG,KAAK,OAAOA,EAAK,QAAQ;AACjF,EAAIF,EAAK,IAAIG,CAAG,MAGhBH,EAAK,IAAIG,CAAG,GACZF,EAAI,KAAKC,CAAI;AACf;AAGO,SAASE,EAAsBC,GAAO;AAC3C,QAAML,wBAAW,IAAA,GACXC,IAAM,CAAA;AACZ,aAAWC,KAAQG,GAAO;AACxB,QAAIH,EAAK,SAAS,gBAAgBA,EAAK,SAAS,mBAAmB;AACjE,MAAAH,EAAWC,GAAMC,GAAKC,CAAI;AAC1B;AAAA,IACF;AAGA,QAAII,EAAaJ,CAAI,KAAKA,EAAK,UAAU,sBAAsBK,EAAoBC,EAAYN,CAAI,CAAC;AAClG,iBAAWO,KAAUC,EAA2BR,EAAK,MAAM;AACzD,QAAAH,EAAWC,GAAMC,GAAK;AAAA,UACpB,MAAM;AAAA,UACN,UAAUQ,EAAO;AAAA,UACjB,KAAKA,EAAO;AAAA,UACZ,OAAOA,EAAO;AAAA,QAAA,CACf;AAAA,EAGP;AACA,SAAOR;AACT;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contextCompactionPart.js","sources":["../../../../src/chat/Message/parts/contextCompactionPart.ts"],"sourcesContent":["import { isDataUIPart } from '
|
|
1
|
+
{"version":3,"file":"contextCompactionPart.js","sources":["../../../../src/chat/Message/parts/contextCompactionPart.ts"],"sourcesContent":["import { isDataUIPart } from '@reforma/types';\n\nimport type { ReformaChatDataContextCompactionPayload } from '@reforma/types';\nimport type { ReformaUIMessagePart } from '../types';\n\nexport type ContextCompactionUIPart = {\n type: 'data-context-compaction';\n data: ReformaChatDataContextCompactionPayload;\n};\n\nexport function isContextCompactionUIPart(\n part: ReformaUIMessagePart\n): part is ContextCompactionUIPart {\n return isDataUIPart(part) && part.type === 'data-context-compaction';\n}\n"],"names":["isContextCompactionUIPart","part","isDataUIPart"],"mappings":";AACO,SAASA,EAA0BC,GAAM;AAC9C,SAAOC,EAAaD,CAAI,KAAKA,EAAK,SAAS;AAC7C;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { plural as a } from "@reforma/lib";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { isToolUIPart as g, getToolName as S } from "@reforma/types";
|
|
3
|
+
import { isScreenshotTool as T } from "@reforma/types/sandbox";
|
|
4
4
|
import { parseCallDynamicToolInput as E, parsePrefixedMcpToolName as x } from "../../Tool/mcp-tools/parseCallDynamicToolInput.js";
|
|
5
5
|
import { readPathsFromPart as y } from "../../Tool/read/normalizeReadTools.js";
|
|
6
6
|
import { mcpGroupedSegmentRole as G } from "./groupedSegmentMcpTools.js";
|
|
@@ -58,9 +58,9 @@ function H(s, t) {
|
|
|
58
58
|
const {
|
|
59
59
|
part: n
|
|
60
60
|
} = p;
|
|
61
|
-
if (!
|
|
61
|
+
if (!g(n))
|
|
62
62
|
continue;
|
|
63
|
-
const r =
|
|
63
|
+
const r = S(n);
|
|
64
64
|
if (r === "CallDynamicTool") {
|
|
65
65
|
const {
|
|
66
66
|
namespace: i,
|
|
@@ -91,7 +91,7 @@ function H(s, t) {
|
|
|
91
91
|
e.hasCommands = !0, e.commandCount++;
|
|
92
92
|
else if (R(r))
|
|
93
93
|
e.hasExplore = !0, e.searchCount++;
|
|
94
|
-
else if (
|
|
94
|
+
else if (T(r))
|
|
95
95
|
e.hasExplore = !0, e.screenshotCount++;
|
|
96
96
|
else if (d(r)) {
|
|
97
97
|
const i = c(n);
|