@assistant-ui/react
Version:
Typescript/React library for AI Chat
129 lines • 5.11 kB
JavaScript
"use client";
import { jsx, jsxs } from "react/jsx-runtime";
import { memo, useMemo } from "react";
import {
TextContentPartProvider,
useContentPart,
useContentPartRuntime,
useToolUIs
} from "../../context";
import {
useMessage,
useMessageRuntime
} from "../../context/react/MessageContext";
import { ContentPartRuntimeProvider } from "../../context/providers/ContentPartRuntimeProvider";
import { ContentPartPrimitiveText } from "../contentPart/ContentPartText";
import { ContentPartPrimitiveImage } from "../contentPart/ContentPartImage";
import { ContentPartPrimitiveInProgress } from "../contentPart/ContentPartInProgress";
const ToolUIDisplay = ({
Fallback,
...props
}) => {
const Render = useToolUIs((s) => s.getToolUI(props.toolName)) ?? Fallback;
if (!Render) return null;
return /* @__PURE__ */ jsx(Render, { ...props });
};
const defaultComponents = {
Text: () => /* @__PURE__ */ jsxs("p", { style: { whiteSpace: "pre-line" }, children: [
/* @__PURE__ */ jsx(ContentPartPrimitiveText, {}),
/* @__PURE__ */ jsx(ContentPartPrimitiveInProgress, { children: /* @__PURE__ */ jsx("span", { style: { fontFamily: "revert" }, children: " \u25CF" }) })
] }),
Reasoning: () => null,
Source: () => null,
Image: () => /* @__PURE__ */ jsx(ContentPartPrimitiveImage, {}),
File: () => null,
Unstable_Audio: () => null
};
const MessageContentPartComponent = ({
components: {
Text = defaultComponents.Text,
Reasoning = defaultComponents.Reasoning,
Image = defaultComponents.Image,
Source = defaultComponents.Source,
File = defaultComponents.File,
Unstable_Audio: Audio = defaultComponents.Unstable_Audio,
tools = {}
} = {}
}) => {
const contentPartRuntime = useContentPartRuntime();
const part = useContentPart();
const type = part.type;
if (type === "tool-call") {
const addResult = (result) => contentPartRuntime.addToolResult(result);
if ("Override" in tools)
return /* @__PURE__ */ jsx(tools.Override, { ...part, addResult });
const Tool = tools.by_name?.[part.toolName] ?? tools.Fallback;
return /* @__PURE__ */ jsx(ToolUIDisplay, { ...part, Fallback: Tool, addResult });
}
if (part.status.type === "requires-action")
throw new Error("Encountered unexpected requires-action status");
switch (type) {
case "text":
return /* @__PURE__ */ jsx(Text, { ...part });
case "reasoning":
return /* @__PURE__ */ jsx(Reasoning, { ...part });
case "source":
return /* @__PURE__ */ jsx(Source, { ...part });
case "image":
return /* @__PURE__ */ jsx(Image, { ...part });
case "file":
return /* @__PURE__ */ jsx(File, { ...part });
case "audio":
return /* @__PURE__ */ jsx(Audio, { ...part });
default:
const unhandledType = type;
throw new Error(`Unknown content part type: ${unhandledType}`);
}
};
const MessageContentPartImpl = ({
partIndex,
components
}) => {
const messageRuntime = useMessageRuntime();
const runtime = useMemo(
() => messageRuntime.getContentPartByIndex(partIndex),
[messageRuntime, partIndex]
);
return /* @__PURE__ */ jsx(ContentPartRuntimeProvider, { runtime, children: /* @__PURE__ */ jsx(MessageContentPartComponent, { components }) });
};
const MessageContentPart = memo(
MessageContentPartImpl,
(prev, next) => prev.partIndex === next.partIndex && prev.components?.Text === next.components?.Text && prev.components?.Reasoning === next.components?.Reasoning && prev.components?.Source === next.components?.Source && prev.components?.Image === next.components?.Image && prev.components?.File === next.components?.File && prev.components?.Unstable_Audio === next.components?.Unstable_Audio && prev.components?.tools === next.components?.tools
);
const COMPLETE_STATUS = Object.freeze({
type: "complete"
});
const EmptyContentFallback = ({ status, component: Component }) => {
return /* @__PURE__ */ jsx(TextContentPartProvider, { text: "", isRunning: status.type === "running", children: /* @__PURE__ */ jsx(Component, { type: "text", text: "", status }) });
};
const EmptyContentImpl = ({
components
}) => {
const status = useMessage((s) => s.status) ?? COMPLETE_STATUS;
if (components?.Empty) return /* @__PURE__ */ jsx(components.Empty, { status });
return /* @__PURE__ */ jsx(
EmptyContentFallback,
{
status,
component: components?.Text ?? defaultComponents.Text
}
);
};
const EmptyContent = memo(
EmptyContentImpl,
(prev, next) => prev.components?.Empty === next.components?.Empty && prev.components?.Text === next.components?.Text
);
const MessagePrimitiveContent = ({
components
}) => {
const contentLength = useMessage((s) => s.content.length);
if (contentLength === 0) {
return /* @__PURE__ */ jsx(EmptyContent, { components });
}
return Array.from({ length: contentLength }, (_, index) => /* @__PURE__ */ jsx(MessageContentPart, { partIndex: index, components }, index));
};
MessagePrimitiveContent.displayName = "MessagePrimitive.Content";
export {
MessagePrimitiveContent
};
//# sourceMappingURL=MessageContent.js.map