Skip to content

Commit 7e53ff8

Browse files
committed
update message request
1 parent 688c55f commit 7e53ff8

27 files changed

+1769
-630
lines changed

.github/workflows/publish.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
2727
gpg-passphrase: MAVEN_GPG_PASSPHRASE
2828
- name: Publish package
29-
run: mvn --batch-mode deploy
29+
run: mvn -Ppublish --batch-mode deploy
3030
env:
3131
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
3232
MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}

app/globals.css

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,68 @@
11
@tailwind base;
22
@tailwind components;
33
@tailwind utilities;
4+
5+
@layer base {
6+
:root {
7+
--background: 0 0% 100%;
8+
--foreground: 240 10% 3.9%;
9+
--card: 0 0% 100%;
10+
--card-foreground: 240 10% 3.9%;
11+
--popover: 0 0% 100%;
12+
--popover-foreground: 240 10% 3.9%;
13+
--primary: 240 5.9% 10%;
14+
--primary-foreground: 0 0% 98%;
15+
--secondary: 240 4.8% 95.9%;
16+
--secondary-foreground: 240 5.9% 10%;
17+
--muted: 240 4.8% 95.9%;
18+
--muted-foreground: 240 3.8% 46.1%;
19+
--accent: 240 4.8% 95.9%;
20+
--accent-foreground: 240 5.9% 10%;
21+
--destructive: 0 84.2% 60.2%;
22+
--destructive-foreground: 0 0% 98%;
23+
--border: 240 5.9% 90%;
24+
--input: 240 5.9% 90%;
25+
--ring: 240 10% 3.9%;
26+
--chart-1: 12 76% 61%;
27+
--chart-2: 173 58% 39%;
28+
--chart-3: 197 37% 24%;
29+
--chart-4: 43 74% 66%;
30+
--chart-5: 27 87% 67%;
31+
--radius: 0.5rem
32+
}
33+
.dark {
34+
--background: 240 10% 3.9%;
35+
--foreground: 0 0% 98%;
36+
--card: 240 10% 3.9%;
37+
--card-foreground: 0 0% 98%;
38+
--popover: 240 10% 3.9%;
39+
--popover-foreground: 0 0% 98%;
40+
--primary: 0 0% 98%;
41+
--primary-foreground: 240 5.9% 10%;
42+
--secondary: 240 3.7% 15.9%;
43+
--secondary-foreground: 0 0% 98%;
44+
--muted: 240 3.7% 15.9%;
45+
--muted-foreground: 240 5% 64.9%;
46+
--accent: 240 3.7% 15.9%;
47+
--accent-foreground: 0 0% 98%;
48+
--destructive: 0 62.8% 30.6%;
49+
--destructive-foreground: 0 0% 98%;
50+
--border: 240 3.7% 15.9%;
51+
--input: 240 3.7% 15.9%;
52+
--ring: 240 4.9% 83.9%;
53+
--chart-1: 220 70% 50%;
54+
--chart-2: 160 60% 45%;
55+
--chart-3: 30 80% 55%;
56+
--chart-4: 280 65% 60%;
57+
--chart-5: 340 75% 55%
58+
}
59+
}
60+
61+
@layer base {
62+
* {
63+
@apply border-border;
64+
}
65+
body {
66+
@apply bg-background text-foreground;
67+
}
68+
}

app/layout.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { Metadata } from "next";
22
import localFont from "next/font/local";
33
import "./globals.css";
4-
import { AgentRuntimeProvider } from "@/components/AgentRuntimeProvider";
54

65
const geistSans = localFont({
76
src: "./fonts/GeistVF.woff",
@@ -25,14 +24,12 @@ export default function RootLayout({
2524
children: React.ReactNode;
2625
}>) {
2726
return (
28-
<AgentRuntimeProvider>
2927
<html lang="en">
3028
<body
3129
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
3230
>
3331
{children}
3432
</body>
3533
</html>
36-
</AgentRuntimeProvider>
3734
);
3835
}

components.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "new-york",
4+
"rsc": true,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "tailwind.config.ts",
8+
"css": "app/globals.css",
9+
"baseColor": "zinc",
10+
"cssVariables": true,
11+
"prefix": ""
12+
},
13+
"aliases": {
14+
"components": "@/components",
15+
"utils": "@/lib/utils",
16+
"ui": "@/components/ui",
17+
"lib": "@/lib",
18+
"hooks": "@/hooks"
19+
},
20+
"iconLibrary": "lucide"
21+
}

components/AgentRuntimeProvider.tsx

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import type { ReactNode } from "react";
44
import {
55
AssistantRuntimeProvider,
6-
TextContentPart,
76
useLocalRuntime,
87
type ChatModelAdapter,
98
} from "@assistant-ui/react";
@@ -16,21 +15,12 @@ const AgentModelAdapter: ChatModelAdapter = {
1615
"Content-Type": "application/json",
1716
},
1817
body: JSON.stringify({
19-
input: (messages[messages.length - 1]?.content[0] as TextContentPart)
20-
?.text,
18+
messages,
2119
}),
2220
signal: abortSignal,
2321
});
2422

25-
const data = await result.json();
26-
return {
27-
content: [
28-
{
29-
type: "text",
30-
text: data.output,
31-
},
32-
],
33-
};
23+
return await result.json();
3424
},
3525
};
3626

components/AgentUI.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
"use client";
22

3-
import { Thread } from "@assistant-ui/react";
4-
import { makeMarkdownText } from "@assistant-ui/react-markdown";
5-
6-
const MarkdownText = makeMarkdownText();
3+
import { AgentRuntimeProvider } from "@/components/AgentRuntimeProvider";
4+
import { ThreadList } from "@/components/assistant-ui/thread-list";
5+
import { Thread } from "@/components/assistant-ui/thread";
76

87
export function AgentUI() {
9-
return <Thread assistantMessage={{ components: { Text: MarkdownText } }} />;
8+
return (
9+
<AgentRuntimeProvider>
10+
<main className="grid h-dvh grid-cols-[200px_1fr] gap-x-2 px-4 py-4">
11+
<ThreadList />
12+
<Thread />
13+
</main>
14+
</AgentRuntimeProvider>
15+
);
1016
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
"use client";
2+
3+
import "@assistant-ui/react-markdown/styles/dot.css";
4+
5+
import {
6+
CodeHeaderProps,
7+
MarkdownTextPrimitive,
8+
unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
9+
useIsMarkdownCodeBlock,
10+
} from "@assistant-ui/react-markdown";
11+
import remarkGfm from "remark-gfm";
12+
import { FC, memo, useState } from "react";
13+
import { CheckIcon, CopyIcon } from "lucide-react";
14+
15+
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
16+
import { cn } from "@/lib/utils";
17+
18+
const MarkdownTextImpl = () => {
19+
return (
20+
<MarkdownTextPrimitive
21+
remarkPlugins={[remarkGfm]}
22+
className="aui-md"
23+
components={defaultComponents}
24+
/>
25+
);
26+
};
27+
28+
export const MarkdownText = memo(MarkdownTextImpl);
29+
30+
const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
31+
const { isCopied, copyToClipboard } = useCopyToClipboard();
32+
const onCopy = () => {
33+
if (!code || isCopied) return;
34+
copyToClipboard(code);
35+
};
36+
37+
return (
38+
<div className="flex items-center justify-between gap-4 rounded-t-lg bg-zinc-900 px-4 py-2 text-sm font-semibold text-white">
39+
<span className="lowercase [&>span]:text-xs">{language}</span>
40+
<TooltipIconButton tooltip="Copy" onClick={onCopy}>
41+
{!isCopied && <CopyIcon />}
42+
{isCopied && <CheckIcon />}
43+
</TooltipIconButton>
44+
</div>
45+
);
46+
};
47+
48+
const useCopyToClipboard = ({
49+
copiedDuration = 3000,
50+
}: {
51+
copiedDuration?: number;
52+
} = {}) => {
53+
const [isCopied, setIsCopied] = useState<boolean>(false);
54+
55+
const copyToClipboard = (value: string) => {
56+
if (!value) return;
57+
58+
navigator.clipboard.writeText(value).then(() => {
59+
setIsCopied(true);
60+
setTimeout(() => setIsCopied(false), copiedDuration);
61+
});
62+
};
63+
64+
return { isCopied, copyToClipboard };
65+
};
66+
67+
const defaultComponents = memoizeMarkdownComponents({
68+
h1: ({ className, ...props }) => (
69+
<h1 className={cn("mb-8 scroll-m-20 text-4xl font-extrabold tracking-tight last:mb-0", className)} {...props} />
70+
),
71+
h2: ({ className, ...props }) => (
72+
<h2 className={cn("mb-4 mt-8 scroll-m-20 text-3xl font-semibold tracking-tight first:mt-0 last:mb-0", className)} {...props} />
73+
),
74+
h3: ({ className, ...props }) => (
75+
<h3 className={cn("mb-4 mt-6 scroll-m-20 text-2xl font-semibold tracking-tight first:mt-0 last:mb-0", className)} {...props} />
76+
),
77+
h4: ({ className, ...props }) => (
78+
<h4 className={cn("mb-4 mt-6 scroll-m-20 text-xl font-semibold tracking-tight first:mt-0 last:mb-0", className)} {...props} />
79+
),
80+
h5: ({ className, ...props }) => (
81+
<h5 className={cn("my-4 text-lg font-semibold first:mt-0 last:mb-0", className)} {...props} />
82+
),
83+
h6: ({ className, ...props }) => (
84+
<h6 className={cn("my-4 font-semibold first:mt-0 last:mb-0", className)} {...props} />
85+
),
86+
p: ({ className, ...props }) => (
87+
<p className={cn("mb-5 mt-5 leading-7 first:mt-0 last:mb-0", className)} {...props} />
88+
),
89+
a: ({ className, ...props }) => (
90+
<a className={cn("text-primary font-medium underline underline-offset-4", className)} {...props} />
91+
),
92+
blockquote: ({ className, ...props }) => (
93+
<blockquote className={cn("border-l-2 pl-6 italic", className)} {...props} />
94+
),
95+
ul: ({ className, ...props }) => (
96+
<ul className={cn("my-5 ml-6 list-disc [&>li]:mt-2", className)} {...props} />
97+
),
98+
ol: ({ className, ...props }) => (
99+
<ol className={cn("my-5 ml-6 list-decimal [&>li]:mt-2", className)} {...props} />
100+
),
101+
hr: ({ className, ...props }) => (
102+
<hr className={cn("my-5 border-b", className)} {...props} />
103+
),
104+
table: ({ className, ...props }) => (
105+
<table className={cn("my-5 w-full border-separate border-spacing-0 overflow-y-auto", className)} {...props} />
106+
),
107+
th: ({ className, ...props }) => (
108+
<th className={cn("bg-muted px-4 py-2 text-left font-bold first:rounded-tl-lg last:rounded-tr-lg [&[align=center]]:text-center [&[align=right]]:text-right", className)} {...props} />
109+
),
110+
td: ({ className, ...props }) => (
111+
<td className={cn("border-b border-l px-4 py-2 text-left last:border-r [&[align=center]]:text-center [&[align=right]]:text-right", className)} {...props} />
112+
),
113+
tr: ({ className, ...props }) => (
114+
<tr className={cn("m-0 border-b p-0 first:border-t [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg", className)} {...props} />
115+
),
116+
sup: ({ className, ...props }) => (
117+
<sup className={cn("[&>a]:text-xs [&>a]:no-underline", className)} {...props} />
118+
),
119+
pre: ({ className, ...props }) => (
120+
<pre className={cn("overflow-x-auto rounded-b-lg bg-black p-4 text-white", className)} {...props} />
121+
),
122+
code: function Code({ className, ...props }) {
123+
const isCodeBlock = useIsMarkdownCodeBlock();
124+
return (
125+
<code
126+
className={cn(!isCodeBlock && "bg-muted rounded border font-semibold", className)}
127+
{...props}
128+
/>
129+
);
130+
},
131+
CodeHeader,
132+
});
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import type { FC } from "react";
2+
import {
3+
ThreadListItemPrimitive,
4+
ThreadListPrimitive,
5+
} from "@assistant-ui/react";
6+
import { ArchiveIcon, PlusIcon } from "lucide-react";
7+
8+
import { Button } from "@/components/ui/button";
9+
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
10+
11+
export const ThreadList: FC = () => {
12+
return (
13+
<ThreadListPrimitive.Root className="flex flex-col items-stretch gap-1.5">
14+
<ThreadListNew />
15+
<ThreadListItems />
16+
</ThreadListPrimitive.Root>
17+
);
18+
};
19+
20+
const ThreadListNew: FC = () => {
21+
return (
22+
<ThreadListPrimitive.New asChild>
23+
<Button className="data-[active]:bg-muted hover:bg-muted flex items-center justify-start gap-1 rounded-lg px-2.5 py-2 text-start" variant="ghost">
24+
<PlusIcon />
25+
New Thread
26+
</Button>
27+
</ThreadListPrimitive.New>
28+
);
29+
};
30+
31+
const ThreadListItems: FC = () => {
32+
return <ThreadListPrimitive.Items components={{ ThreadListItem }} />;
33+
};
34+
35+
const ThreadListItem: FC = () => {
36+
return (
37+
<ThreadListItemPrimitive.Root className="data-[active]:bg-muted hover:bg-muted focus-visible:bg-muted focus-visible:ring-ring flex items-center gap-2 rounded-lg transition-all focus-visible:outline-none focus-visible:ring-2">
38+
<ThreadListItemPrimitive.Trigger className="flex-grow px-3 py-2 text-start">
39+
<ThreadListItemTitle />
40+
</ThreadListItemPrimitive.Trigger>
41+
<ThreadListItemArchive />
42+
</ThreadListItemPrimitive.Root>
43+
);
44+
};
45+
46+
const ThreadListItemTitle: FC = () => {
47+
return (
48+
<p className="text-sm">
49+
<ThreadListItemPrimitive.Title fallback="New Chat" />
50+
</p>
51+
);
52+
};
53+
54+
const ThreadListItemArchive: FC = () => {
55+
return (
56+
<ThreadListItemPrimitive.Archive asChild>
57+
<TooltipIconButton
58+
className="hover:text-primary text-foreground ml-auto mr-3 size-4 p-0"
59+
variant="ghost"
60+
tooltip="Archive thread"
61+
>
62+
<ArchiveIcon />
63+
</TooltipIconButton>
64+
</ThreadListItemPrimitive.Archive>
65+
);
66+
};

0 commit comments

Comments
 (0)