Files
agent-chat-ui/agent/uis/open-code/proposed-change/index.tsx

118 lines
3.6 KiB
TypeScript
Raw Normal View History

2025-03-07 10:47:08 -08:00
import "./index.css";
2025-03-07 11:21:49 -08:00
import { v4 as uuidv4 } from "uuid";
import { Button } from "@/components/ui/button";
2025-03-07 10:47:08 -08:00
import ReactMarkdown from "react-markdown";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { coldarkDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
2025-03-07 11:21:49 -08:00
import { UIMessage, useStreamContext } from "@langchain/langgraph-sdk/react-ui";
import { Message } from "@langchain/langgraph-sdk";
import { DO_NOT_RENDER_ID_PREFIX } from "@/lib/ensure-tool-responses";
import { useState } from "react";
2025-03-07 10:47:08 -08:00
interface ProposedChangeProps {
toolCallId: string;
change: string;
planItem: string;
}
export default function ProposedChange(props: ProposedChangeProps) {
2025-03-07 11:21:49 -08:00
const [isAccepted, setIsAccepted] = useState(false);
const thread = useStreamContext<
{ messages: Message[]; ui: UIMessage[] },
{ MetaType: { ui: UIMessage | undefined } }
>();
const handleReject = () => {
alert("Rejected. (just kidding, you can't reject me silly!)");
};
const handleAccept = () => {
const content = "User accepted the proposed change. Please continue.";
thread.submit({
messages: [
{
type: "tool",
tool_call_id: props.toolCallId,
id: `${DO_NOT_RENDER_ID_PREFIX}${uuidv4()}`,
name: "buy-stock",
content,
},
{
type: "human",
content: `Accepted change.`,
},
],
});
setIsAccepted(true);
};
if (isAccepted) {
return (
<div className="flex flex-col gap-4 w-full max-w-xl p-4 border-[1px] rounded-xl border-green-300">
<div className="flex flex-col items-start justify-start gap-2">
<p className="text-lg font-medium">Accepted Change</p>
<p className="text-sm font-mono">{props.planItem}</p>
</div>
<ReactMarkdown
children={props.change}
components={{
code(props) {
const { children, className, node: _node } = props;
const match = /language-(\w+)/.exec(className || "");
return match ? (
<SyntaxHighlighter
children={String(children).replace(/\n$/, "")}
language={match[1]}
style={coldarkDark}
/>
) : (
<code className={className}>{children}</code>
);
},
}}
/>
</div>
);
}
2025-03-07 10:47:08 -08:00
return (
2025-03-07 11:21:49 -08:00
<div className="flex flex-col gap-4 w-full max-w-4xl p-4 border-[1px] rounded-xl border-slate-200">
<div className="flex flex-col items-start justify-start gap-2">
<p className="text-lg font-medium">Proposed Change</p>
<p className="text-sm font-mono">{props.planItem}</p>
</div>
2025-03-07 10:47:08 -08:00
<ReactMarkdown
children={props.change}
components={{
code(props) {
const { children, className, node: _node } = props;
const match = /language-(\w+)/.exec(className || "");
return match ? (
<SyntaxHighlighter
children={String(children).replace(/\n$/, "")}
language={match[1]}
style={coldarkDark}
/>
) : (
<code className={className}>{children}</code>
);
},
}}
/>
<div className="flex gap-2 items-center w-full">
2025-03-07 11:21:49 -08:00
<Button
className="cursor-pointer"
variant="destructive"
onClick={handleReject}
>
2025-03-07 10:47:08 -08:00
Reject
</Button>
2025-03-07 11:21:49 -08:00
<Button className="cursor-pointer" onClick={handleAccept}>
Accept
</Button>
2025-03-07 10:47:08 -08:00
</div>
</div>
);
}