@assistant-ui/react-native 0.1.40 → 0.1.41
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/primitives/message/MessageContent.d.ts.map +1 -1
- package/dist/primitives/message/MessageContent.js +1 -1
- package/dist/primitives/message/MessageContent.js.map +1 -1
- package/dist/primitives/message/MessageParts.js +2 -14
- package/dist/primitives/message/MessageParts.js.map +1 -1
- package/package.json +7 -7
- package/src/primitives/message/MessageContent.runtime.test.tsx +81 -0
- package/src/primitives/message/MessageContent.test.tsx +6 -1
- package/src/primitives/message/MessageContent.tsx +13 -7
- package/src/primitives/message/MessageParts.test.tsx +116 -0
- package/src/primitives/message/MessageParts.tsx +1 -24
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageContent.d.ts","names":[],"sources":["../../../src/primitives/message/MessageContent.tsx"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"MessageContent.d.ts","names":[],"sources":["../../../src/primitives/message/MessageContent.tsx"],"mappings":";;;KAaK,qBAAqB,wBAAwB;KAGtC;EACV,cAAc;IACZ,MAAM,QAAQ;MAAsB;;IACpC;QACI;EACN,kBAAkB;IAChB,MAAM,QAAQ;MAAsB;;IACpC;QACI;EACN,eAAe;IACb,MAAM,QAAQ;MAAsB;;IACpC;QACI;EACN,mBAAmB;IACjB,MAAM,QAAQ;MAAsB;;IACpC;QACI;EACN,gBAAgB;IACd,MAAM,QAAQ;MAAsB;;IACpC;QACI;EACN,cAAc;IACZ,MAAM,QAAQ;MAAsB;;IACpC;QACI;EACN,cAAc;IACZ,MAAM,QAAQ;MAAsB;;IACpC;QACI;;cAsEK,mBAAkB,YAAA,gBAAA,aAAA,iBAAA,cAAA,YAAA,cAQ5B,wCAAmB,IAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageContent.js","names":["ReactElement","Fragment","useMemo","Text","ThreadUserMessagePart","ThreadAssistantMessagePart","ToolCallMessagePart","DataMessagePart","useAui","useAuiState","ToolCallMessagePartProps","DataMessagePartProps","MessageContentPart","MessageContentProps","renderText","props","part","Extract","type","index","renderToolCall","renderImage","renderReasoning","renderSource","renderFile","renderData","DefaultTextRenderer","t0","$","_c","t1","text","ToolUIDisplay","Fallback","aui","toolName","s","tools","toolUIs","render","Render","t2","message","partMethods","t3","t4","addToolResult","respondToToolApproval","resumeToolCall","DataUIDisplay","name","renders","dataRenderers","renderers","Array","isArray","MessageContent","content","_temp","key","map"],"sources":["../../../src/primitives/message/MessageContent.tsx"],"sourcesContent":["import { type ReactElement, Fragment, useMemo } from \"react\";\nimport { Text } from \"react-native\";\nimport type {\n ThreadUserMessagePart,\n ThreadAssistantMessagePart,\n ToolCallMessagePart,\n DataMessagePart,\n} from \"@assistant-ui/core\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport type {\n ToolCallMessagePartProps,\n DataMessagePartProps,\n} from \"@assistant-ui/core/react\";\n\ntype MessageContentPart = ThreadUserMessagePart | ThreadAssistantMessagePart;\n\nexport type MessageContentProps = {\n renderText?: (props: {\n part: Extract<MessageContentPart, { type: \"text\" }>;\n index: number;\n }) => ReactElement;\n renderToolCall?: (props: {\n part: Extract<MessageContentPart, { type: \"tool-call\" }>;\n index: number;\n }) => ReactElement;\n renderImage?: (props: {\n part: Extract<MessageContentPart, { type: \"image\" }>;\n index: number;\n }) => ReactElement;\n renderReasoning?: (props: {\n part: Extract<MessageContentPart, { type: \"reasoning\" }>;\n index: number;\n }) => ReactElement;\n renderSource?: (props: {\n part: Extract<MessageContentPart, { type: \"source\" }>;\n index: number;\n }) => ReactElement;\n renderFile?: (props: {\n part: Extract<MessageContentPart, { type: \"file\" }>;\n index: number;\n }) => ReactElement;\n renderData?: (props: {\n part: Extract<MessageContentPart, { type: \"data\" }>;\n index: number;\n }) => ReactElement;\n};\n\nconst DefaultTextRenderer = ({\n part,\n}: {\n part: Extract<MessageContentPart, { type: \"text\" }>;\n}) => {\n return <Text>{part.text}</Text>;\n};\n\nconst ToolUIDisplay = ({\n Fallback,\n part,\n index,\n}: {\n Fallback:\n | ((props: { part: ToolCallMessagePart; index: number }) => ReactElement)\n | undefined;\n part: ToolCallMessagePart;\n index: number;\n}) => {\n const aui = useAui();\n const Render = useAuiState(\n (s) => s.tools.toolUIs[part.toolName]?.[0]?.render,\n );\n\n const partMethods = useMemo(() => aui.message.part({ index }), [aui, index]);\n\n if (Render) {\n return (\n <Render\n {...(part as ToolCallMessagePartProps)}\n addResult={partMethods.addToolResult}\n resume={partMethods.resumeToolCall}\n respondToApproval={partMethods.respondToToolApproval}\n />\n );\n }\n if (Fallback) return <Fallback part={part} index={index} />;\n return null;\n};\n\nconst DataUIDisplay = ({\n Fallback,\n part,\n index,\n}: {\n Fallback:\n | ((props: { part: DataMessagePart; index: number }) => ReactElement)\n | undefined;\n part: DataMessagePart;\n index: number;\n}) => {\n const Render = useAuiState((s) => {\n const renders = s.dataRenderers.renderers[part.name];\n if (Array.isArray(renders)) return renders[0];\n return renders;\n });\n if (Render) return <Render {...(part as DataMessagePartProps)} />;\n if (Fallback) return <Fallback part={part} index={index} />;\n return null;\n};\n\nexport const MessageContent = ({\n renderText,\n renderToolCall,\n renderImage,\n renderReasoning,\n renderSource,\n renderFile,\n renderData,\n}: MessageContentProps) => {\n const content = useAuiState((s) => s.message.content);\n\n return (\n <>\n {content.map((part, index) => {\n const key = `${part.type}-${index}`;\n switch (part.type) {\n case \"text\":\n return (\n <Fragment key={key}>\n {renderText ? (\n renderText({ part, index })\n ) : (\n <DefaultTextRenderer part={part} />\n )}\n </Fragment>\n );\n case \"tool-call\":\n return (\n <Fragment key={key}>\n <ToolUIDisplay\n Fallback={renderToolCall}\n part={part}\n index={index}\n />\n </Fragment>\n );\n case \"image\":\n if (!renderImage) return null;\n return (\n <Fragment key={key}>{renderImage({ part, index })}</Fragment>\n );\n case \"reasoning\":\n if (!renderReasoning) return null;\n return (\n <Fragment key={key}>{renderReasoning({ part, index })}</Fragment>\n );\n case \"source\":\n if (!renderSource) return null;\n return (\n <Fragment key={key}>{renderSource({ part, index })}</Fragment>\n );\n case \"file\":\n if (!renderFile) return null;\n return <Fragment key={key}>{renderFile({ part, index })}</Fragment>;\n case \"data\":\n return (\n <Fragment key={key}>\n <DataUIDisplay\n Fallback={renderData}\n part={part}\n index={index}\n />\n </Fragment>\n );\n default:\n return null;\n }\n })}\n </>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MessageContent.js","names":["ReactElement","Fragment","useMemo","Text","ThreadUserMessagePart","ThreadAssistantMessagePart","MessagePartState","useAui","useAuiState","ToolCallMessagePartProps","DataMessagePartProps","MessageContentPart","MessageContentStatePart","MessageContentProps","renderText","props","part","Extract","type","index","renderToolCall","renderImage","renderReasoning","renderSource","renderFile","renderData","DefaultTextRenderer","t0","$","_c","t1","text","ToolUIDisplay","Fallback","aui","toolName","s","tools","toolUIs","render","Render","t2","message","partMethods","t3","t4","addToolResult","respondToToolApproval","resumeToolCall","DataUIDisplay","name","renders","dataRenderers","renderers","Array","isArray","MessageContent","content","_temp","key","map","parts"],"sources":["../../../src/primitives/message/MessageContent.tsx"],"sourcesContent":["import { type ReactElement, Fragment, useMemo } from \"react\";\nimport { Text } from \"react-native\";\nimport type {\n ThreadUserMessagePart,\n ThreadAssistantMessagePart,\n MessagePartState,\n} from \"@assistant-ui/core\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport type {\n ToolCallMessagePartProps,\n DataMessagePartProps,\n} from \"@assistant-ui/core/react\";\n\ntype MessageContentPart = ThreadUserMessagePart | ThreadAssistantMessagePart;\ntype MessageContentStatePart = MessagePartState;\n\nexport type MessageContentProps = {\n renderText?: (props: {\n part: Extract<MessageContentPart, { type: \"text\" }>;\n index: number;\n }) => ReactElement;\n renderToolCall?: (props: {\n part: Extract<MessageContentPart, { type: \"tool-call\" }>;\n index: number;\n }) => ReactElement;\n renderImage?: (props: {\n part: Extract<MessageContentPart, { type: \"image\" }>;\n index: number;\n }) => ReactElement;\n renderReasoning?: (props: {\n part: Extract<MessageContentPart, { type: \"reasoning\" }>;\n index: number;\n }) => ReactElement;\n renderSource?: (props: {\n part: Extract<MessageContentPart, { type: \"source\" }>;\n index: number;\n }) => ReactElement;\n renderFile?: (props: {\n part: Extract<MessageContentPart, { type: \"file\" }>;\n index: number;\n }) => ReactElement;\n renderData?: (props: {\n part: Extract<MessageContentPart, { type: \"data\" }>;\n index: number;\n }) => ReactElement;\n};\n\nconst DefaultTextRenderer = ({\n part,\n}: {\n part: Extract<MessageContentPart, { type: \"text\" }>;\n}) => {\n return <Text>{part.text}</Text>;\n};\n\nconst ToolUIDisplay = ({\n Fallback,\n part,\n index,\n}: {\n Fallback:\n | ((props: {\n part: Extract<MessageContentPart, { type: \"tool-call\" }>;\n index: number;\n }) => ReactElement)\n | undefined;\n part: Extract<MessageContentStatePart, { type: \"tool-call\" }>;\n index: number;\n}) => {\n const aui = useAui();\n const Render = useAuiState(\n (s) => s.tools.toolUIs[part.toolName]?.[0]?.render,\n );\n\n const partMethods = useMemo(() => aui.message.part({ index }), [aui, index]);\n\n if (Render) {\n return (\n <Render\n {...(part as ToolCallMessagePartProps)}\n addResult={partMethods.addToolResult}\n resume={partMethods.resumeToolCall}\n respondToApproval={partMethods.respondToToolApproval}\n />\n );\n }\n if (Fallback) return <Fallback part={part} index={index} />;\n return null;\n};\n\nconst DataUIDisplay = ({\n Fallback,\n part,\n index,\n}: {\n Fallback:\n | ((props: {\n part: Extract<MessageContentPart, { type: \"data\" }>;\n index: number;\n }) => ReactElement)\n | undefined;\n part: Extract<MessageContentStatePart, { type: \"data\" }>;\n index: number;\n}) => {\n const Render = useAuiState((s) => {\n const renders = s.dataRenderers.renderers[part.name];\n if (Array.isArray(renders)) return renders[0];\n return renders;\n });\n if (Render) return <Render {...(part as DataMessagePartProps)} />;\n if (Fallback) return <Fallback part={part} index={index} />;\n return null;\n};\n\nexport const MessageContent = ({\n renderText,\n renderToolCall,\n renderImage,\n renderReasoning,\n renderSource,\n renderFile,\n renderData,\n}: MessageContentProps) => {\n const content = useAuiState((s) => s.message.parts);\n\n return (\n <>\n {content.map((part, index) => {\n const key = `${part.type}-${index}`;\n switch (part.type) {\n case \"text\":\n return (\n <Fragment key={key}>\n {renderText ? (\n renderText({ part, index })\n ) : (\n <DefaultTextRenderer part={part} />\n )}\n </Fragment>\n );\n case \"tool-call\":\n return (\n <Fragment key={key}>\n <ToolUIDisplay\n Fallback={renderToolCall}\n part={part}\n index={index}\n />\n </Fragment>\n );\n case \"image\":\n if (!renderImage) return null;\n return (\n <Fragment key={key}>{renderImage({ part, index })}</Fragment>\n );\n case \"reasoning\":\n if (!renderReasoning) return null;\n return (\n <Fragment key={key}>{renderReasoning({ part, index })}</Fragment>\n );\n case \"source\":\n if (!renderSource) return null;\n return (\n <Fragment key={key}>{renderSource({ part, index })}</Fragment>\n );\n case \"file\":\n if (!renderFile) return null;\n return <Fragment key={key}>{renderFile({ part, index })}</Fragment>;\n case \"data\":\n return (\n <Fragment key={key}>\n <DataUIDisplay\n Fallback={renderData}\n part={part}\n index={index}\n />\n </Fragment>\n );\n default:\n return null;\n }\n })}\n </>\n );\n};\n"],"mappings":"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"}
|
|
@@ -35,20 +35,8 @@ const MessagePrimitiveParts = (props) => {
|
|
|
35
35
|
let t0;
|
|
36
36
|
if ($[5] !== components) {
|
|
37
37
|
t0 = components ? {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Reasoning: components.Reasoning ?? messagePartsDefaultComponents.Reasoning,
|
|
41
|
-
Source: components.Source ?? messagePartsDefaultComponents.Source,
|
|
42
|
-
File: components.File ?? messagePartsDefaultComponents.File,
|
|
43
|
-
Unstable_Audio: components.Unstable_Audio ?? messagePartsDefaultComponents.Unstable_Audio,
|
|
44
|
-
..."ChainOfThought" in components ? { ChainOfThought: components.ChainOfThought } : {
|
|
45
|
-
tools: components.tools,
|
|
46
|
-
data: components.data,
|
|
47
|
-
ToolGroup: components.ToolGroup ?? messagePartsDefaultComponents.ToolGroup,
|
|
48
|
-
ReasoningGroup: components.ReasoningGroup ?? messagePartsDefaultComponents.ReasoningGroup
|
|
49
|
-
},
|
|
50
|
-
Empty: components.Empty,
|
|
51
|
-
Quote: components.Quote
|
|
38
|
+
...components,
|
|
39
|
+
Text: components.Text ?? rnDefaultComponents.Text
|
|
52
40
|
} : rnDefaultComponents;
|
|
53
41
|
$[5] = components;
|
|
54
42
|
$[6] = t0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageParts.js","names":["FC","Text","MessagePrimitiveParts","MessagePrimitivePartsBase","MessagePartComponent","MessagePartComponentBase","MessagePrimitivePartByIndex","MessagePrimitivePartByIndexBase","messagePartsDefaultComponents","rnDefaultComponents","text","Props","props","$","_c","t0","children","components","rest","
|
|
1
|
+
{"version":3,"file":"MessageParts.js","names":["FC","Text","MessagePrimitiveParts","MessagePrimitivePartsBase","MessagePartComponent","MessagePartComponentBase","MessagePrimitivePartByIndex","MessagePrimitivePartByIndexBase","messagePartsDefaultComponents","rnDefaultComponents","text","Props","props","$","_c","t0","children","components","rest","merged","t1","t2","displayName"],"sources":["../../../src/primitives/message/MessageParts.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { Text } from \"react-native\";\nimport {\n MessagePrimitiveParts as MessagePrimitivePartsBase,\n MessagePartComponent as MessagePartComponentBase,\n MessagePrimitivePartByIndex as MessagePrimitivePartByIndexBase,\n messagePartsDefaultComponents,\n} from \"@assistant-ui/core/react\";\n\nconst rnDefaultComponents = {\n ...messagePartsDefaultComponents,\n Text: ({ text }: { text: string }) => <Text>{text}</Text>,\n} satisfies MessagePrimitiveParts.Props[\"components\"];\n\nexport namespace MessagePrimitiveParts {\n export type Props = MessagePrimitivePartsBase.Props;\n}\n\n/**\n * Renders the parts of a message with React Native-specific default components.\n */\nexport const MessagePrimitiveParts: FC<MessagePrimitiveParts.Props> = (\n props,\n) => {\n if (\"children\" in props) {\n return (\n <MessagePrimitivePartsBase>{props.children}</MessagePrimitivePartsBase>\n );\n }\n\n const { components, ...rest } = props;\n const merged = components\n ? { ...components, Text: components.Text ?? rnDefaultComponents.Text }\n : rnDefaultComponents;\n\n return <MessagePrimitivePartsBase components={merged as any} {...rest} />;\n};\n\nMessagePrimitiveParts.displayName = \"MessagePrimitive.Parts\";\n\nexport {\n MessagePartComponentBase as MessagePartComponent,\n MessagePrimitivePartByIndexBase as MessagePrimitivePartByIndex,\n};\n"],"mappings":";;;;;AASA,MAAMS,sBAAsB;CAC1B,GAAGD;CACHP,OAAO,EAAES,WAA6B,oBAAC,MAAD,EAAA,UAAOA,KAAW,CAAA;AAC1D;;;;AASA,MAAaR,yBAAyDU,UAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CAGpE,IAAI,cAAcF,OAAK;EAAA,IAAAG;EAAA,IAAAF,EAAA,OAAAD,MAAAI,UAAA;GAEnBD,KAAA,oBAAC,yBAAD,EAAA,UAA4BH,MAAKI,SAAP,CAAA;GAA6CH,EAAA,KAAAD,MAAAI;GAAAH,EAAA,KAAAE;EAAA,OAAAA,KAAAF,EAAA;EAAA,OAAvEE;CAAuE;CAE1E,IAAAE;CAAA,IAAAC;CAAA,IAAAL,EAAA,OAAAD,OAAA;EAED,CAAA,CAAAK,YAAA,GAAAC,QAAgCN;EAAMC,EAAA,KAAAD;EAAAC,EAAA,KAAAI;EAAAJ,EAAA,KAAAK;CAAA,OAAA;EAAAD,aAAAJ,EAAA;EAAAK,OAAAL,EAAA;CAAA;CAAA,IAAAE;CAAA,IAAAF,EAAA,OAAAI,YAAA;EACvBF,KAAAE,aAAA;GAAA,GACNA;GAAUhB,MAAQgB,WAAUhB,QAASQ,oBAAmBR;EAC3C,IAFPQ;EAEQI,EAAA,KAAAI;EAAAJ,EAAA,KAAAE;CAAA,OAAAA,KAAAF,EAAA;CAEuB,MAAAO,KAAAD;CAAa,IAAAE;CAAA,IAAAR,EAAA,OAAAK,QAAAL,EAAA,OAAAO,IAAA;EAApDC,KAAA,oBAAC,yBAAD;GAAuC,YAAAD;GAAa,GAAMF;EAAI,CAAA;EAAIL,EAAA,KAAAK;EAAAL,EAAA,KAAAO;EAAAP,EAAA,KAAAQ;CAAA,OAAAA,KAAAR,EAAA;CAAA,OAAlEQ;AAAkE;AAG3EnB,sBAAsBoB,cAAc"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/react-native",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.41",
|
|
4
4
|
"description": "React Native bindings for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"assistant",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
],
|
|
32
32
|
"sideEffects": false,
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@assistant-ui/core": "^0.3.
|
|
35
|
-
"@assistant-ui/store": "^0.3.
|
|
36
|
-
"@assistant-ui/tap": "^0.9.
|
|
37
|
-
"assistant-stream": "^0.3.
|
|
34
|
+
"@assistant-ui/core": "^0.3.18",
|
|
35
|
+
"@assistant-ui/store": "^0.3.13",
|
|
36
|
+
"@assistant-ui/tap": "^0.9.17",
|
|
37
|
+
"assistant-stream": "^0.3.42"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"@types/react": "*",
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
50
|
+
"@assistant-ui/x-buildutils": "0.0.26",
|
|
51
51
|
"@babel/core": "^7.29.7",
|
|
52
52
|
"@types/react": "^19.2.18",
|
|
53
|
-
"@types/react-dom": "^19.2.
|
|
53
|
+
"@types/react-dom": "^19.2.7",
|
|
54
54
|
"jsdom": "^30.0.1",
|
|
55
55
|
"react": "^19.2.8",
|
|
56
56
|
"react-dom": "^19.2.8",
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { act } from "react";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import type { MessagePartState, ThreadMessageLike } from "@assistant-ui/core";
|
|
5
|
+
import {
|
|
6
|
+
AssistantRuntimeProvider,
|
|
7
|
+
MessageByIndexProvider,
|
|
8
|
+
useAssistantDataUI,
|
|
9
|
+
useAssistantToolUI,
|
|
10
|
+
useExternalStoreRuntime,
|
|
11
|
+
} from "@assistant-ui/core/react";
|
|
12
|
+
import { MessageContent } from "./MessageContent";
|
|
13
|
+
|
|
14
|
+
(globalThis as Record<string, unknown>).IS_REACT_ACT_ENVIRONMENT = true;
|
|
15
|
+
|
|
16
|
+
describe("MessageContent with a runtime", () => {
|
|
17
|
+
it.each(["tool-call", "data"] as const)(
|
|
18
|
+
"renders derived status for registered %s UIs",
|
|
19
|
+
async (type) => {
|
|
20
|
+
const Status = ({ status }: Pick<MessagePartState, "status">) => (
|
|
21
|
+
<span>{status.type}</span>
|
|
22
|
+
);
|
|
23
|
+
const Registrations = () => {
|
|
24
|
+
useAssistantToolUI({ toolName: "search", render: Status });
|
|
25
|
+
useAssistantDataUI({ name: "chart", render: Status });
|
|
26
|
+
return <MessageContent />;
|
|
27
|
+
};
|
|
28
|
+
const App = ({ message }: { message: ThreadMessageLike }) => {
|
|
29
|
+
const runtime = useExternalStoreRuntime({
|
|
30
|
+
messages: [message],
|
|
31
|
+
convertMessage: (value) => value,
|
|
32
|
+
onNew: async () => {},
|
|
33
|
+
});
|
|
34
|
+
return (
|
|
35
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
36
|
+
<MessageByIndexProvider index={0}>
|
|
37
|
+
<Registrations />
|
|
38
|
+
</MessageByIndexProvider>
|
|
39
|
+
</AssistantRuntimeProvider>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
const container = document.createElement("div");
|
|
43
|
+
const root = createRoot(container);
|
|
44
|
+
try {
|
|
45
|
+
for (const status of [
|
|
46
|
+
"running",
|
|
47
|
+
"requires-action",
|
|
48
|
+
"complete",
|
|
49
|
+
] as const) {
|
|
50
|
+
if (type === "data" && status === "requires-action") continue;
|
|
51
|
+
const message: ThreadMessageLike = {
|
|
52
|
+
id: "m1",
|
|
53
|
+
role: "assistant",
|
|
54
|
+
status:
|
|
55
|
+
status === "running"
|
|
56
|
+
? { type: status }
|
|
57
|
+
: status === "complete"
|
|
58
|
+
? { type: status, reason: "stop" }
|
|
59
|
+
: { type: status, reason: "tool-calls" },
|
|
60
|
+
content: [
|
|
61
|
+
type === "data"
|
|
62
|
+
? { type, name: "chart", data: { value: 1 } }
|
|
63
|
+
: {
|
|
64
|
+
type,
|
|
65
|
+
toolName: "search",
|
|
66
|
+
toolCallId: "c1",
|
|
67
|
+
args: {},
|
|
68
|
+
argsText: "{}",
|
|
69
|
+
...(status === "complete" ? { result: "done" } : {}),
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
await act(async () => root.render(<App message={message} />));
|
|
74
|
+
expect(container.textContent).toBe(status);
|
|
75
|
+
}
|
|
76
|
+
} finally {
|
|
77
|
+
await act(async () => root.unmount());
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
});
|
|
@@ -10,7 +10,12 @@ const h = vi.hoisted(() => ({
|
|
|
10
10
|
resumeToolCall: vi.fn(),
|
|
11
11
|
respondToToolApproval: vi.fn(),
|
|
12
12
|
state: {
|
|
13
|
-
message: {
|
|
13
|
+
message: {
|
|
14
|
+
content: [] as AnyPart[],
|
|
15
|
+
get parts() {
|
|
16
|
+
return this.content;
|
|
17
|
+
},
|
|
18
|
+
},
|
|
14
19
|
tools: { toolUIs: {} as Record<string, unknown> },
|
|
15
20
|
dataRenderers: { renderers: {} as Record<string, unknown> },
|
|
16
21
|
},
|
|
@@ -3,8 +3,7 @@ import { Text } from "react-native";
|
|
|
3
3
|
import type {
|
|
4
4
|
ThreadUserMessagePart,
|
|
5
5
|
ThreadAssistantMessagePart,
|
|
6
|
-
|
|
7
|
-
DataMessagePart,
|
|
6
|
+
MessagePartState,
|
|
8
7
|
} from "@assistant-ui/core";
|
|
9
8
|
import { useAui, useAuiState } from "@assistant-ui/store";
|
|
10
9
|
import type {
|
|
@@ -13,6 +12,7 @@ import type {
|
|
|
13
12
|
} from "@assistant-ui/core/react";
|
|
14
13
|
|
|
15
14
|
type MessageContentPart = ThreadUserMessagePart | ThreadAssistantMessagePart;
|
|
15
|
+
type MessageContentStatePart = MessagePartState;
|
|
16
16
|
|
|
17
17
|
export type MessageContentProps = {
|
|
18
18
|
renderText?: (props: {
|
|
@@ -59,9 +59,12 @@ const ToolUIDisplay = ({
|
|
|
59
59
|
index,
|
|
60
60
|
}: {
|
|
61
61
|
Fallback:
|
|
62
|
-
| ((props: {
|
|
62
|
+
| ((props: {
|
|
63
|
+
part: Extract<MessageContentPart, { type: "tool-call" }>;
|
|
64
|
+
index: number;
|
|
65
|
+
}) => ReactElement)
|
|
63
66
|
| undefined;
|
|
64
|
-
part:
|
|
67
|
+
part: Extract<MessageContentStatePart, { type: "tool-call" }>;
|
|
65
68
|
index: number;
|
|
66
69
|
}) => {
|
|
67
70
|
const aui = useAui();
|
|
@@ -91,9 +94,12 @@ const DataUIDisplay = ({
|
|
|
91
94
|
index,
|
|
92
95
|
}: {
|
|
93
96
|
Fallback:
|
|
94
|
-
| ((props: {
|
|
97
|
+
| ((props: {
|
|
98
|
+
part: Extract<MessageContentPart, { type: "data" }>;
|
|
99
|
+
index: number;
|
|
100
|
+
}) => ReactElement)
|
|
95
101
|
| undefined;
|
|
96
|
-
part:
|
|
102
|
+
part: Extract<MessageContentStatePart, { type: "data" }>;
|
|
97
103
|
index: number;
|
|
98
104
|
}) => {
|
|
99
105
|
const Render = useAuiState((s) => {
|
|
@@ -115,7 +121,7 @@ export const MessageContent = ({
|
|
|
115
121
|
renderFile,
|
|
116
122
|
renderData,
|
|
117
123
|
}: MessageContentProps) => {
|
|
118
|
-
const content = useAuiState((s) => s.message.
|
|
124
|
+
const content = useAuiState((s) => s.message.parts);
|
|
119
125
|
|
|
120
126
|
return (
|
|
121
127
|
<>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { act } from "react";
|
|
2
|
+
import { createRoot, type Root } from "react-dom/client";
|
|
3
|
+
import { Text } from "react-native";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
5
|
+
import type { ThreadMessageLike } from "@assistant-ui/core";
|
|
6
|
+
import {
|
|
7
|
+
AssistantRuntimeProvider,
|
|
8
|
+
MessageByIndexProvider,
|
|
9
|
+
useExternalStoreRuntime,
|
|
10
|
+
} from "@assistant-ui/core/react";
|
|
11
|
+
import { MessagePrimitiveParts } from "./MessageParts";
|
|
12
|
+
|
|
13
|
+
(globalThis as Record<string, unknown>).IS_REACT_ACT_ENVIRONMENT = true;
|
|
14
|
+
|
|
15
|
+
const messages: ThreadMessageLike[] = [
|
|
16
|
+
{
|
|
17
|
+
role: "assistant",
|
|
18
|
+
content: [
|
|
19
|
+
{ type: "text", text: "Answer" },
|
|
20
|
+
{ type: "reasoning", text: "Thinking" },
|
|
21
|
+
{
|
|
22
|
+
type: "generative-ui",
|
|
23
|
+
spec: {
|
|
24
|
+
root: [
|
|
25
|
+
{ component: "Card", props: { title: "Result" } },
|
|
26
|
+
{ component: "Unknown" },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{ type: "data", name: "chart", data: 42 },
|
|
31
|
+
{ type: "data", name: "other", data: 7 },
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const components = {
|
|
37
|
+
generativeUI: {
|
|
38
|
+
components: {
|
|
39
|
+
Card: ({ title }: { title: string }) => <Text>{title}</Text>,
|
|
40
|
+
},
|
|
41
|
+
Fallback: ({ component }: { component: string }) => (
|
|
42
|
+
<Text>Unavailable: {component}</Text>
|
|
43
|
+
),
|
|
44
|
+
},
|
|
45
|
+
data: {
|
|
46
|
+
by_name: {
|
|
47
|
+
chart: ({ data }: { data: unknown }) => (
|
|
48
|
+
<Text>Chart: {String(data)}</Text>
|
|
49
|
+
),
|
|
50
|
+
},
|
|
51
|
+
Fallback: ({ data }: { data: unknown }) => (
|
|
52
|
+
<Text>Data: {String(data)}</Text>
|
|
53
|
+
),
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const App = (props: MessagePrimitiveParts.Props) => {
|
|
58
|
+
const runtime = useExternalStoreRuntime({
|
|
59
|
+
messages,
|
|
60
|
+
convertMessage: (message) => message,
|
|
61
|
+
onNew: async () => {
|
|
62
|
+
throw new Error("This thread is read-only");
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
return (
|
|
66
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
67
|
+
<MessageByIndexProvider index={0}>
|
|
68
|
+
<MessagePrimitiveParts {...props} />
|
|
69
|
+
</MessageByIndexProvider>
|
|
70
|
+
</AssistantRuntimeProvider>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const ChainOfThought = () => <Text>Thought group</Text>;
|
|
75
|
+
|
|
76
|
+
describe("MessagePrimitiveParts", () => {
|
|
77
|
+
let container: HTMLDivElement;
|
|
78
|
+
let root: Root;
|
|
79
|
+
|
|
80
|
+
beforeEach(() => {
|
|
81
|
+
container = document.createElement("div");
|
|
82
|
+
document.body.appendChild(container);
|
|
83
|
+
root = createRoot(container);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
afterEach(async () => {
|
|
87
|
+
await act(async () => root.unmount());
|
|
88
|
+
container.remove();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("renders generative UI and its fallback beside native text", async () => {
|
|
92
|
+
await act(async () => root.render(<App components={components} />));
|
|
93
|
+
expect(container.textContent).toBe(
|
|
94
|
+
"AnswerResultUnavailable: UnknownChart: 42Data: 7",
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("keeps data and generative UI when chain-of-thought grouping changes", async () => {
|
|
99
|
+
await act(async () => root.render(<App components={components} />));
|
|
100
|
+
expect(container.textContent).toBe(
|
|
101
|
+
"AnswerResultUnavailable: UnknownChart: 42Data: 7",
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
await act(async () =>
|
|
105
|
+
root.render(<App components={{ ...components, ChainOfThought }} />),
|
|
106
|
+
);
|
|
107
|
+
expect(container.textContent).toBe(
|
|
108
|
+
"AnswerThought groupResultUnavailable: UnknownChart: 42Data: 7",
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
await act(async () => root.render(<App components={components} />));
|
|
112
|
+
expect(container.textContent).toBe(
|
|
113
|
+
"AnswerResultUnavailable: UnknownChart: 42Data: 7",
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -30,30 +30,7 @@ export const MessagePrimitiveParts: FC<MessagePrimitiveParts.Props> = (
|
|
|
30
30
|
|
|
31
31
|
const { components, ...rest } = props;
|
|
32
32
|
const merged = components
|
|
33
|
-
? {
|
|
34
|
-
Text: components.Text ?? rnDefaultComponents.Text,
|
|
35
|
-
Image: components.Image ?? messagePartsDefaultComponents.Image,
|
|
36
|
-
Reasoning:
|
|
37
|
-
components.Reasoning ?? messagePartsDefaultComponents.Reasoning,
|
|
38
|
-
Source: components.Source ?? messagePartsDefaultComponents.Source,
|
|
39
|
-
File: components.File ?? messagePartsDefaultComponents.File,
|
|
40
|
-
Unstable_Audio:
|
|
41
|
-
components.Unstable_Audio ??
|
|
42
|
-
messagePartsDefaultComponents.Unstable_Audio,
|
|
43
|
-
...("ChainOfThought" in components
|
|
44
|
-
? { ChainOfThought: components.ChainOfThought }
|
|
45
|
-
: {
|
|
46
|
-
tools: components.tools,
|
|
47
|
-
data: components.data,
|
|
48
|
-
ToolGroup:
|
|
49
|
-
components.ToolGroup ?? messagePartsDefaultComponents.ToolGroup,
|
|
50
|
-
ReasoningGroup:
|
|
51
|
-
components.ReasoningGroup ??
|
|
52
|
-
messagePartsDefaultComponents.ReasoningGroup,
|
|
53
|
-
}),
|
|
54
|
-
Empty: components.Empty,
|
|
55
|
-
Quote: components.Quote,
|
|
56
|
-
}
|
|
33
|
+
? { ...components, Text: components.Text ?? rnDefaultComponents.Text }
|
|
57
34
|
: rnDefaultComponents;
|
|
58
35
|
|
|
59
36
|
return <MessagePrimitivePartsBase components={merged as any} {...rest} />;
|