langwatch 0.2.0 → 0.3.0-prerelease.2
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/LICENSE +7 -0
- package/README.md +268 -1
- package/dist/chunk-4BZATFKJ.mjs +181 -0
- package/dist/chunk-4BZATFKJ.mjs.map +1 -0
- package/dist/chunk-CSC3CMIT.mjs +118 -0
- package/dist/chunk-CSC3CMIT.mjs.map +1 -0
- package/dist/chunk-F63YKTXA.mjs +47 -0
- package/dist/chunk-F63YKTXA.mjs.map +1 -0
- package/dist/chunk-G3AUABT7.js +4 -0
- package/dist/chunk-G3AUABT7.js.map +1 -0
- package/dist/chunk-HPC6Z7J4.js +118 -0
- package/dist/chunk-HPC6Z7J4.js.map +1 -0
- package/dist/chunk-KGDAENGD.js +50 -0
- package/dist/chunk-KGDAENGD.js.map +1 -0
- package/dist/chunk-LD74LVRU.js +47 -0
- package/dist/chunk-LD74LVRU.js.map +1 -0
- package/dist/chunk-OM7VY3XT.mjs +4 -0
- package/dist/chunk-PCQVQ7SB.js +45 -0
- package/dist/chunk-PCQVQ7SB.js.map +1 -0
- package/dist/chunk-PMBEK6YE.mjs +424 -0
- package/dist/chunk-PMBEK6YE.mjs.map +1 -0
- package/dist/chunk-PR3JDWC3.mjs +50 -0
- package/dist/chunk-PR3JDWC3.mjs.map +1 -0
- package/dist/chunk-PTJ6AAI7.js +360 -0
- package/dist/chunk-PTJ6AAI7.js.map +1 -0
- package/dist/chunk-QEWDG5QE.mjs +45 -0
- package/dist/chunk-QEWDG5QE.mjs.map +1 -0
- package/dist/chunk-REUCVT7A.mjs +39 -0
- package/dist/chunk-REUCVT7A.mjs.map +1 -0
- package/dist/chunk-SVJ7SCGB.js +424 -0
- package/dist/chunk-SVJ7SCGB.js.map +1 -0
- package/dist/chunk-VJSOCNPA.js +181 -0
- package/dist/chunk-VJSOCNPA.js.map +1 -0
- package/dist/chunk-WM2GRSRW.js +39 -0
- package/dist/chunk-WM2GRSRW.js.map +1 -0
- package/dist/chunk-Z5J5UI5E.mjs +360 -0
- package/dist/chunk-Z5J5UI5E.mjs.map +1 -0
- package/dist/client-B2HqIKg6.d.ts +51 -0
- package/dist/client-XyCqclCi.d.mts +51 -0
- package/dist/client-browser.d.mts +8 -0
- package/dist/client-browser.d.ts +8 -0
- package/dist/client-browser.js +83 -0
- package/dist/client-browser.js.map +1 -0
- package/dist/client-browser.mjs +83 -0
- package/dist/client-browser.mjs.map +1 -0
- package/dist/client-node.d.mts +8 -0
- package/dist/client-node.d.ts +8 -0
- package/dist/client-node.js +90 -0
- package/dist/client-node.js.map +1 -0
- package/dist/client-node.mjs +90 -0
- package/dist/client-node.mjs.map +1 -0
- package/dist/evaluation/index.d.mts +897 -0
- package/dist/evaluation/index.d.ts +897 -0
- package/dist/evaluation/index.js +13 -0
- package/dist/evaluation/index.js.map +1 -0
- package/dist/evaluation/index.mjs +13 -0
- package/dist/evaluation/index.mjs.map +1 -0
- package/dist/filterable-batch-span-processor-zO5kcjBY.d.mts +64 -0
- package/dist/filterable-batch-span-processor-zO5kcjBY.d.ts +64 -0
- package/dist/index.d.mts +45 -1027
- package/dist/index.d.ts +45 -1027
- package/dist/index.js +11 -27291
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +23 -956
- package/dist/index.mjs.map +1 -1
- package/dist/observability/index.d.mts +260 -0
- package/dist/observability/index.d.ts +260 -0
- package/dist/observability/index.js +20 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/index.mjs +20 -0
- package/dist/observability/index.mjs.map +1 -0
- package/dist/observability/instrumentation/langchain/index.d.mts +40 -0
- package/dist/observability/instrumentation/langchain/index.d.ts +40 -0
- package/dist/observability/instrumentation/langchain/index.js +666 -0
- package/dist/observability/instrumentation/langchain/index.js.map +1 -0
- package/dist/observability/instrumentation/langchain/index.mjs +666 -0
- package/dist/observability/instrumentation/langchain/index.mjs.map +1 -0
- package/dist/prompt/index.d.mts +10 -0
- package/dist/prompt/index.d.ts +10 -0
- package/dist/prompt/index.js +18 -0
- package/dist/prompt/index.js.map +1 -0
- package/dist/prompt/index.mjs +18 -0
- package/dist/prompt/index.mjs.map +1 -0
- package/dist/prompt-BXJWdbQp.d.mts +1967 -0
- package/dist/prompt-BXJWdbQp.d.ts +1967 -0
- package/dist/record-evaluation-CmxMXa-3.d.mts +25 -0
- package/dist/record-evaluation-CmxMXa-3.d.ts +25 -0
- package/dist/trace-D-bZOuqb.d.mts +622 -0
- package/dist/trace-G2312klE.d.ts +622 -0
- package/package.json +86 -37
- package/.eslintrc.cjs +0 -37
- package/copy-types.sh +0 -17
- package/dist/chunk-LKD2K67J.mjs +0 -717
- package/dist/chunk-LKD2K67J.mjs.map +0 -1
- package/dist/utils-Cv-rUjJ1.d.mts +0 -313
- package/dist/utils-Cv-rUjJ1.d.ts +0 -313
- package/dist/utils.d.mts +0 -2
- package/dist/utils.d.ts +0 -2
- package/dist/utils.js +0 -709
- package/dist/utils.js.map +0 -1
- package/dist/utils.mjs +0 -11
- package/example/.env.example +0 -12
- package/example/.eslintrc.json +0 -26
- package/example/LICENSE +0 -13
- package/example/README.md +0 -12
- package/example/app/(chat)/chat/[id]/page.tsx +0 -60
- package/example/app/(chat)/layout.tsx +0 -14
- package/example/app/(chat)/page.tsx +0 -27
- package/example/app/actions.ts +0 -156
- package/example/app/globals.css +0 -76
- package/example/app/guardrails/page.tsx +0 -26
- package/example/app/langchain/page.tsx +0 -27
- package/example/app/langchain-rag/page.tsx +0 -28
- package/example/app/late-update/page.tsx +0 -27
- package/example/app/layout.tsx +0 -64
- package/example/app/login/actions.ts +0 -71
- package/example/app/login/page.tsx +0 -18
- package/example/app/manual/page.tsx +0 -27
- package/example/app/new/page.tsx +0 -5
- package/example/app/opengraph-image.png +0 -0
- package/example/app/share/[id]/page.tsx +0 -58
- package/example/app/signup/actions.ts +0 -111
- package/example/app/signup/page.tsx +0 -18
- package/example/app/twitter-image.png +0 -0
- package/example/auth.config.ts +0 -42
- package/example/auth.ts +0 -45
- package/example/components/button-scroll-to-bottom.tsx +0 -36
- package/example/components/chat-history.tsx +0 -49
- package/example/components/chat-list.tsx +0 -52
- package/example/components/chat-message-actions.tsx +0 -40
- package/example/components/chat-message.tsx +0 -80
- package/example/components/chat-panel.tsx +0 -139
- package/example/components/chat-share-dialog.tsx +0 -95
- package/example/components/chat.tsx +0 -84
- package/example/components/clear-history.tsx +0 -75
- package/example/components/empty-screen.tsx +0 -38
- package/example/components/external-link.tsx +0 -29
- package/example/components/footer.tsx +0 -19
- package/example/components/header.tsx +0 -114
- package/example/components/login-button.tsx +0 -42
- package/example/components/login-form.tsx +0 -97
- package/example/components/markdown.tsx +0 -9
- package/example/components/prompt-form.tsx +0 -115
- package/example/components/providers.tsx +0 -17
- package/example/components/sidebar-actions.tsx +0 -125
- package/example/components/sidebar-desktop.tsx +0 -19
- package/example/components/sidebar-footer.tsx +0 -16
- package/example/components/sidebar-item.tsx +0 -124
- package/example/components/sidebar-items.tsx +0 -42
- package/example/components/sidebar-list.tsx +0 -38
- package/example/components/sidebar-mobile.tsx +0 -31
- package/example/components/sidebar-toggle.tsx +0 -24
- package/example/components/sidebar.tsx +0 -21
- package/example/components/signup-form.tsx +0 -95
- package/example/components/stocks/events-skeleton.tsx +0 -31
- package/example/components/stocks/events.tsx +0 -30
- package/example/components/stocks/index.tsx +0 -36
- package/example/components/stocks/message.tsx +0 -134
- package/example/components/stocks/spinner.tsx +0 -16
- package/example/components/stocks/stock-purchase.tsx +0 -146
- package/example/components/stocks/stock-skeleton.tsx +0 -22
- package/example/components/stocks/stock.tsx +0 -210
- package/example/components/stocks/stocks-skeleton.tsx +0 -9
- package/example/components/stocks/stocks.tsx +0 -67
- package/example/components/tailwind-indicator.tsx +0 -14
- package/example/components/theme-toggle.tsx +0 -31
- package/example/components/ui/alert-dialog.tsx +0 -141
- package/example/components/ui/badge.tsx +0 -36
- package/example/components/ui/button.tsx +0 -57
- package/example/components/ui/codeblock.tsx +0 -148
- package/example/components/ui/dialog.tsx +0 -122
- package/example/components/ui/dropdown-menu.tsx +0 -205
- package/example/components/ui/icons.tsx +0 -507
- package/example/components/ui/input.tsx +0 -25
- package/example/components/ui/label.tsx +0 -26
- package/example/components/ui/select.tsx +0 -164
- package/example/components/ui/separator.tsx +0 -31
- package/example/components/ui/sheet.tsx +0 -140
- package/example/components/ui/sonner.tsx +0 -31
- package/example/components/ui/switch.tsx +0 -29
- package/example/components/ui/textarea.tsx +0 -24
- package/example/components/ui/tooltip.tsx +0 -30
- package/example/components/user-menu.tsx +0 -53
- package/example/components.json +0 -17
- package/example/instrumentation.ts +0 -11
- package/example/lib/chat/guardrails.tsx +0 -181
- package/example/lib/chat/langchain-rag.tsx +0 -191
- package/example/lib/chat/langchain.tsx +0 -112
- package/example/lib/chat/late-update.tsx +0 -208
- package/example/lib/chat/manual.tsx +0 -605
- package/example/lib/chat/vercel-ai.tsx +0 -576
- package/example/lib/hooks/use-copy-to-clipboard.tsx +0 -33
- package/example/lib/hooks/use-enter-submit.tsx +0 -23
- package/example/lib/hooks/use-local-storage.ts +0 -24
- package/example/lib/hooks/use-scroll-anchor.tsx +0 -86
- package/example/lib/hooks/use-sidebar.tsx +0 -60
- package/example/lib/hooks/use-streamable-text.ts +0 -25
- package/example/lib/types.ts +0 -41
- package/example/lib/utils.ts +0 -89
- package/example/middleware.ts +0 -8
- package/example/next-env.d.ts +0 -5
- package/example/next.config.js +0 -16
- package/example/package-lock.json +0 -10917
- package/example/package.json +0 -84
- package/example/pnpm-lock.yaml +0 -5712
- package/example/postcss.config.js +0 -6
- package/example/prettier.config.cjs +0 -34
- package/example/public/apple-touch-icon.png +0 -0
- package/example/public/favicon-16x16.png +0 -0
- package/example/public/favicon.ico +0 -0
- package/example/public/next.svg +0 -1
- package/example/public/thirteen.svg +0 -1
- package/example/public/vercel.svg +0 -1
- package/example/tailwind.config.ts +0 -81
- package/example/tsconfig.json +0 -35
- package/src/LangWatchExporter.ts +0 -96
- package/src/evaluations.ts +0 -219
- package/src/index.test.ts +0 -402
- package/src/index.ts +0 -596
- package/src/langchain.ts +0 -557
- package/src/server/types/.gitkeep +0 -0
- package/src/typeUtils.ts +0 -89
- package/src/types.ts +0 -82
- package/src/utils.ts +0 -205
- package/ts-to-zod.config.js +0 -24
- package/tsconfig.json +0 -32
- package/tsup.config.ts +0 -10
- package/vitest.config.ts +0 -8
- /package/dist/{utils.mjs.map → chunk-OM7VY3XT.mjs.map} +0 -0
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as React from 'react'
|
|
4
|
-
import { signIn } from 'next-auth/react'
|
|
5
|
-
|
|
6
|
-
import { cn } from '@/lib/utils'
|
|
7
|
-
import { Button, type ButtonProps } from '@/components/ui/button'
|
|
8
|
-
import { IconGitHub, IconSpinner } from '@/components/ui/icons'
|
|
9
|
-
|
|
10
|
-
interface LoginButtonProps extends ButtonProps {
|
|
11
|
-
showGithubIcon?: boolean
|
|
12
|
-
text?: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function LoginButton({
|
|
16
|
-
text = 'Login with GitHub',
|
|
17
|
-
showGithubIcon = true,
|
|
18
|
-
className,
|
|
19
|
-
...props
|
|
20
|
-
}: LoginButtonProps) {
|
|
21
|
-
const [isLoading, setIsLoading] = React.useState(false)
|
|
22
|
-
return (
|
|
23
|
-
<Button
|
|
24
|
-
variant="outline"
|
|
25
|
-
onClick={() => {
|
|
26
|
-
setIsLoading(true)
|
|
27
|
-
// next-auth signIn() function doesn't work yet at Edge Runtime due to usage of BroadcastChannel
|
|
28
|
-
signIn('github', { callbackUrl: `/` })
|
|
29
|
-
}}
|
|
30
|
-
disabled={isLoading}
|
|
31
|
-
className={cn(className)}
|
|
32
|
-
{...props}
|
|
33
|
-
>
|
|
34
|
-
{isLoading ? (
|
|
35
|
-
<IconSpinner className="mr-2 animate-spin" />
|
|
36
|
-
) : showGithubIcon ? (
|
|
37
|
-
<IconGitHub className="mr-2" />
|
|
38
|
-
) : null}
|
|
39
|
-
{text}
|
|
40
|
-
</Button>
|
|
41
|
-
)
|
|
42
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useFormState, useFormStatus } from 'react-dom'
|
|
4
|
-
import { authenticate } from '@/app/login/actions'
|
|
5
|
-
import Link from 'next/link'
|
|
6
|
-
import { useEffect } from 'react'
|
|
7
|
-
import { toast } from 'sonner'
|
|
8
|
-
import { IconSpinner } from './ui/icons'
|
|
9
|
-
import { getMessageFromCode } from '@/lib/utils'
|
|
10
|
-
import { useRouter } from 'next/navigation'
|
|
11
|
-
|
|
12
|
-
export default function LoginForm() {
|
|
13
|
-
const router = useRouter()
|
|
14
|
-
const [result, dispatch] = useFormState(authenticate, undefined)
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
if (result) {
|
|
18
|
-
if (result.type === 'error') {
|
|
19
|
-
toast.error(getMessageFromCode(result.resultCode))
|
|
20
|
-
} else {
|
|
21
|
-
toast.success(getMessageFromCode(result.resultCode))
|
|
22
|
-
router.refresh()
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}, [result, router])
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
<form
|
|
29
|
-
action={dispatch}
|
|
30
|
-
className="flex flex-col items-center gap-4 space-y-3"
|
|
31
|
-
>
|
|
32
|
-
<div className="w-full flex-1 rounded-lg border bg-white px-6 pb-4 pt-8 shadow-md md:w-96 dark:bg-zinc-950">
|
|
33
|
-
<h1 className="mb-3 text-2xl font-bold">Please log in to continue.</h1>
|
|
34
|
-
<div className="w-full">
|
|
35
|
-
<div>
|
|
36
|
-
<label
|
|
37
|
-
className="mb-3 mt-5 block text-xs font-medium text-zinc-400"
|
|
38
|
-
htmlFor="email"
|
|
39
|
-
>
|
|
40
|
-
Email
|
|
41
|
-
</label>
|
|
42
|
-
<div className="relative">
|
|
43
|
-
<input
|
|
44
|
-
className="peer block w-full rounded-md border bg-zinc-50 px-2 py-[9px] text-sm outline-none placeholder:text-zinc-500 dark:border-zinc-800 dark:bg-zinc-950"
|
|
45
|
-
id="email"
|
|
46
|
-
type="email"
|
|
47
|
-
name="email"
|
|
48
|
-
placeholder="Enter your email address"
|
|
49
|
-
required
|
|
50
|
-
/>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
<div className="mt-4">
|
|
54
|
-
<label
|
|
55
|
-
className="mb-3 mt-5 block text-xs font-medium text-zinc-400"
|
|
56
|
-
htmlFor="password"
|
|
57
|
-
>
|
|
58
|
-
Password
|
|
59
|
-
</label>
|
|
60
|
-
<div className="relative">
|
|
61
|
-
<input
|
|
62
|
-
className="peer block w-full rounded-md border bg-zinc-50 px-2 py-[9px] text-sm outline-none placeholder:text-zinc-500 dark:border-zinc-800 dark:bg-zinc-950"
|
|
63
|
-
id="password"
|
|
64
|
-
type="password"
|
|
65
|
-
name="password"
|
|
66
|
-
placeholder="Enter password"
|
|
67
|
-
required
|
|
68
|
-
minLength={6}
|
|
69
|
-
/>
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
72
|
-
</div>
|
|
73
|
-
<LoginButton />
|
|
74
|
-
</div>
|
|
75
|
-
|
|
76
|
-
<Link
|
|
77
|
-
href="/signup"
|
|
78
|
-
className="flex flex-row gap-1 text-sm text-zinc-400"
|
|
79
|
-
>
|
|
80
|
-
No account yet? <div className="font-semibold underline">Sign up</div>
|
|
81
|
-
</Link>
|
|
82
|
-
</form>
|
|
83
|
-
)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function LoginButton() {
|
|
87
|
-
const { pending } = useFormStatus()
|
|
88
|
-
|
|
89
|
-
return (
|
|
90
|
-
<button
|
|
91
|
-
className="my-4 flex h-10 w-full flex-row items-center justify-center rounded-md bg-zinc-900 p-2 text-sm font-semibold text-zinc-100 hover:bg-zinc-800 dark:bg-zinc-100 dark:text-zinc-900 dark:hover:bg-zinc-200"
|
|
92
|
-
aria-disabled={pending}
|
|
93
|
-
>
|
|
94
|
-
{pending ? <IconSpinner /> : 'Log in'}
|
|
95
|
-
</button>
|
|
96
|
-
)
|
|
97
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { FC, memo } from 'react'
|
|
2
|
-
import ReactMarkdown, { Options } from 'react-markdown'
|
|
3
|
-
|
|
4
|
-
export const MemoizedReactMarkdown: FC<Options> = memo(
|
|
5
|
-
ReactMarkdown,
|
|
6
|
-
(prevProps, nextProps) =>
|
|
7
|
-
prevProps.children === nextProps.children &&
|
|
8
|
-
prevProps.className === nextProps.className
|
|
9
|
-
)
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as React from 'react'
|
|
4
|
-
import Textarea from 'react-textarea-autosize'
|
|
5
|
-
|
|
6
|
-
import { useActions, useUIState } from 'ai/rsc'
|
|
7
|
-
|
|
8
|
-
import { UserMessage } from './stocks/message'
|
|
9
|
-
import { type AI } from '@/lib/chat/vercel-ai'
|
|
10
|
-
import { Button } from '@/components/ui/button'
|
|
11
|
-
import { IconArrowElbow, IconPlus } from '@/components/ui/icons'
|
|
12
|
-
import {
|
|
13
|
-
Tooltip,
|
|
14
|
-
TooltipContent,
|
|
15
|
-
TooltipTrigger
|
|
16
|
-
} from '@/components/ui/tooltip'
|
|
17
|
-
import { useEnterSubmit } from '@/lib/hooks/use-enter-submit'
|
|
18
|
-
import { nanoid } from 'nanoid'
|
|
19
|
-
import { useRouter } from 'next/navigation'
|
|
20
|
-
|
|
21
|
-
export function PromptForm({
|
|
22
|
-
input,
|
|
23
|
-
setInput
|
|
24
|
-
}: {
|
|
25
|
-
input: string
|
|
26
|
-
setInput: (value: string) => void
|
|
27
|
-
}) {
|
|
28
|
-
const router = useRouter()
|
|
29
|
-
const { formRef, onKeyDown } = useEnterSubmit()
|
|
30
|
-
const inputRef = React.useRef<HTMLTextAreaElement>(null)
|
|
31
|
-
const { submitUserMessage } = useActions()
|
|
32
|
-
const [_, setMessages] = useUIState<typeof AI>()
|
|
33
|
-
|
|
34
|
-
React.useEffect(() => {
|
|
35
|
-
if (inputRef.current) {
|
|
36
|
-
inputRef.current.focus()
|
|
37
|
-
}
|
|
38
|
-
}, [])
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<form
|
|
42
|
-
ref={formRef}
|
|
43
|
-
onSubmit={async (e: any) => {
|
|
44
|
-
e.preventDefault()
|
|
45
|
-
|
|
46
|
-
// Blur focus on mobile
|
|
47
|
-
if (window.innerWidth < 600) {
|
|
48
|
-
e.target['message']?.blur()
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const value = input.trim()
|
|
52
|
-
setInput('')
|
|
53
|
-
if (!value) return
|
|
54
|
-
|
|
55
|
-
// Optimistically add user message UI
|
|
56
|
-
setMessages(currentMessages => [
|
|
57
|
-
...currentMessages,
|
|
58
|
-
{
|
|
59
|
-
id: nanoid(),
|
|
60
|
-
display: <UserMessage>{value}</UserMessage>
|
|
61
|
-
}
|
|
62
|
-
])
|
|
63
|
-
|
|
64
|
-
// Submit and get response message
|
|
65
|
-
const responseMessage = await submitUserMessage(value)
|
|
66
|
-
setMessages(currentMessages => [...currentMessages, responseMessage])
|
|
67
|
-
}}
|
|
68
|
-
>
|
|
69
|
-
<div className="relative flex max-h-60 w-full grow flex-col overflow-hidden bg-background px-8 sm:rounded-md sm:border sm:px-12">
|
|
70
|
-
<Tooltip>
|
|
71
|
-
<TooltipTrigger asChild>
|
|
72
|
-
<Button
|
|
73
|
-
variant="outline"
|
|
74
|
-
size="icon"
|
|
75
|
-
className="absolute left-0 top-[14px] size-8 rounded-full bg-background p-0 sm:left-4"
|
|
76
|
-
onClick={() => {
|
|
77
|
-
router.push('/new')
|
|
78
|
-
}}
|
|
79
|
-
>
|
|
80
|
-
<IconPlus />
|
|
81
|
-
<span className="sr-only">New Chat</span>
|
|
82
|
-
</Button>
|
|
83
|
-
</TooltipTrigger>
|
|
84
|
-
<TooltipContent>New Chat</TooltipContent>
|
|
85
|
-
</Tooltip>
|
|
86
|
-
<Textarea
|
|
87
|
-
ref={inputRef}
|
|
88
|
-
tabIndex={0}
|
|
89
|
-
onKeyDown={onKeyDown}
|
|
90
|
-
placeholder="Send a message."
|
|
91
|
-
className="min-h-[60px] w-full resize-none bg-transparent px-4 py-[1.3rem] focus-within:outline-none sm:text-sm"
|
|
92
|
-
autoFocus
|
|
93
|
-
spellCheck={false}
|
|
94
|
-
autoComplete="off"
|
|
95
|
-
autoCorrect="off"
|
|
96
|
-
name="message"
|
|
97
|
-
rows={1}
|
|
98
|
-
value={input}
|
|
99
|
-
onChange={e => setInput(e.target.value)}
|
|
100
|
-
/>
|
|
101
|
-
<div className="absolute right-0 top-[13px] sm:right-4">
|
|
102
|
-
<Tooltip>
|
|
103
|
-
<TooltipTrigger asChild>
|
|
104
|
-
<Button type="submit" size="icon" disabled={input === ''}>
|
|
105
|
-
<IconArrowElbow />
|
|
106
|
-
<span className="sr-only">Send message</span>
|
|
107
|
-
</Button>
|
|
108
|
-
</TooltipTrigger>
|
|
109
|
-
<TooltipContent>Send message</TooltipContent>
|
|
110
|
-
</Tooltip>
|
|
111
|
-
</div>
|
|
112
|
-
</div>
|
|
113
|
-
</form>
|
|
114
|
-
)
|
|
115
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as React from 'react'
|
|
4
|
-
import { ThemeProvider as NextThemesProvider } from 'next-themes'
|
|
5
|
-
import { ThemeProviderProps } from 'next-themes/dist/types'
|
|
6
|
-
import { SidebarProvider } from '@/lib/hooks/use-sidebar'
|
|
7
|
-
import { TooltipProvider } from '@/components/ui/tooltip'
|
|
8
|
-
|
|
9
|
-
export function Providers({ children, ...props }: ThemeProviderProps) {
|
|
10
|
-
return (
|
|
11
|
-
<NextThemesProvider {...props}>
|
|
12
|
-
<SidebarProvider>
|
|
13
|
-
<TooltipProvider>{children}</TooltipProvider>
|
|
14
|
-
</SidebarProvider>
|
|
15
|
-
</NextThemesProvider>
|
|
16
|
-
)
|
|
17
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useRouter } from 'next/navigation'
|
|
4
|
-
import * as React from 'react'
|
|
5
|
-
import { toast } from 'sonner'
|
|
6
|
-
|
|
7
|
-
import { ServerActionResult, type Chat } from '@/lib/types'
|
|
8
|
-
import {
|
|
9
|
-
AlertDialog,
|
|
10
|
-
AlertDialogAction,
|
|
11
|
-
AlertDialogCancel,
|
|
12
|
-
AlertDialogContent,
|
|
13
|
-
AlertDialogDescription,
|
|
14
|
-
AlertDialogFooter,
|
|
15
|
-
AlertDialogHeader,
|
|
16
|
-
AlertDialogTitle
|
|
17
|
-
} from '@/components/ui/alert-dialog'
|
|
18
|
-
import { Button } from '@/components/ui/button'
|
|
19
|
-
import { IconShare, IconSpinner, IconTrash } from '@/components/ui/icons'
|
|
20
|
-
import { ChatShareDialog } from '@/components/chat-share-dialog'
|
|
21
|
-
import {
|
|
22
|
-
Tooltip,
|
|
23
|
-
TooltipContent,
|
|
24
|
-
TooltipTrigger
|
|
25
|
-
} from '@/components/ui/tooltip'
|
|
26
|
-
|
|
27
|
-
interface SidebarActionsProps {
|
|
28
|
-
chat: Chat
|
|
29
|
-
removeChat: (args: { id: string; path: string }) => ServerActionResult<void>
|
|
30
|
-
shareChat: (id: string) => ServerActionResult<Chat>
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function SidebarActions({
|
|
34
|
-
chat,
|
|
35
|
-
removeChat,
|
|
36
|
-
shareChat
|
|
37
|
-
}: SidebarActionsProps) {
|
|
38
|
-
const router = useRouter()
|
|
39
|
-
const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false)
|
|
40
|
-
const [shareDialogOpen, setShareDialogOpen] = React.useState(false)
|
|
41
|
-
const [isRemovePending, startRemoveTransition] = React.useTransition()
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<>
|
|
45
|
-
<div className="">
|
|
46
|
-
<Tooltip>
|
|
47
|
-
<TooltipTrigger asChild>
|
|
48
|
-
<Button
|
|
49
|
-
variant="ghost"
|
|
50
|
-
className="size-7 p-0 hover:bg-background"
|
|
51
|
-
onClick={() => setShareDialogOpen(true)}
|
|
52
|
-
>
|
|
53
|
-
<IconShare />
|
|
54
|
-
<span className="sr-only">Share</span>
|
|
55
|
-
</Button>
|
|
56
|
-
</TooltipTrigger>
|
|
57
|
-
<TooltipContent>Share chat</TooltipContent>
|
|
58
|
-
</Tooltip>
|
|
59
|
-
<Tooltip>
|
|
60
|
-
<TooltipTrigger asChild>
|
|
61
|
-
<Button
|
|
62
|
-
variant="ghost"
|
|
63
|
-
className="size-7 p-0 hover:bg-background"
|
|
64
|
-
disabled={isRemovePending}
|
|
65
|
-
onClick={() => setDeleteDialogOpen(true)}
|
|
66
|
-
>
|
|
67
|
-
<IconTrash />
|
|
68
|
-
<span className="sr-only">Delete</span>
|
|
69
|
-
</Button>
|
|
70
|
-
</TooltipTrigger>
|
|
71
|
-
<TooltipContent>Delete chat</TooltipContent>
|
|
72
|
-
</Tooltip>
|
|
73
|
-
</div>
|
|
74
|
-
<ChatShareDialog
|
|
75
|
-
chat={chat}
|
|
76
|
-
shareChat={shareChat}
|
|
77
|
-
open={shareDialogOpen}
|
|
78
|
-
onOpenChange={setShareDialogOpen}
|
|
79
|
-
onCopy={() => setShareDialogOpen(false)}
|
|
80
|
-
/>
|
|
81
|
-
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
|
|
82
|
-
<AlertDialogContent>
|
|
83
|
-
<AlertDialogHeader>
|
|
84
|
-
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
|
|
85
|
-
<AlertDialogDescription>
|
|
86
|
-
This will permanently delete your chat message and remove your
|
|
87
|
-
data from our servers.
|
|
88
|
-
</AlertDialogDescription>
|
|
89
|
-
</AlertDialogHeader>
|
|
90
|
-
<AlertDialogFooter>
|
|
91
|
-
<AlertDialogCancel disabled={isRemovePending}>
|
|
92
|
-
Cancel
|
|
93
|
-
</AlertDialogCancel>
|
|
94
|
-
<AlertDialogAction
|
|
95
|
-
disabled={isRemovePending}
|
|
96
|
-
onClick={event => {
|
|
97
|
-
event.preventDefault()
|
|
98
|
-
// @ts-ignore
|
|
99
|
-
startRemoveTransition(async () => {
|
|
100
|
-
const result = await removeChat({
|
|
101
|
-
id: chat.id,
|
|
102
|
-
path: chat.path
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
if (result && 'error' in result) {
|
|
106
|
-
toast.error(result.error)
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
setDeleteDialogOpen(false)
|
|
111
|
-
router.refresh()
|
|
112
|
-
router.push('/')
|
|
113
|
-
toast.success('Chat deleted')
|
|
114
|
-
})
|
|
115
|
-
}}
|
|
116
|
-
>
|
|
117
|
-
{isRemovePending && <IconSpinner className="mr-2 animate-spin" />}
|
|
118
|
-
Delete
|
|
119
|
-
</AlertDialogAction>
|
|
120
|
-
</AlertDialogFooter>
|
|
121
|
-
</AlertDialogContent>
|
|
122
|
-
</AlertDialog>
|
|
123
|
-
</>
|
|
124
|
-
)
|
|
125
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Sidebar } from '@/components/sidebar'
|
|
2
|
-
|
|
3
|
-
import { auth } from '@/auth'
|
|
4
|
-
import { ChatHistory } from '@/components/chat-history'
|
|
5
|
-
|
|
6
|
-
export async function SidebarDesktop() {
|
|
7
|
-
const session = await auth()
|
|
8
|
-
|
|
9
|
-
if (!session?.user?.id) {
|
|
10
|
-
return null
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<Sidebar className="peer absolute inset-y-0 z-30 hidden -translate-x-full border-r bg-muted duration-300 ease-in-out data-[state=open]:translate-x-0 lg:flex lg:w-[250px] xl:w-[300px]">
|
|
15
|
-
{/* @ts-ignore */}
|
|
16
|
-
<ChatHistory userId={session.user.id} />
|
|
17
|
-
</Sidebar>
|
|
18
|
-
)
|
|
19
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { cn } from '@/lib/utils'
|
|
2
|
-
|
|
3
|
-
export function SidebarFooter({
|
|
4
|
-
children,
|
|
5
|
-
className,
|
|
6
|
-
...props
|
|
7
|
-
}: React.ComponentProps<'div'>) {
|
|
8
|
-
return (
|
|
9
|
-
<div
|
|
10
|
-
className={cn('flex items-center justify-between p-4', className)}
|
|
11
|
-
{...props}
|
|
12
|
-
>
|
|
13
|
-
{children}
|
|
14
|
-
</div>
|
|
15
|
-
)
|
|
16
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as React from 'react'
|
|
4
|
-
|
|
5
|
-
import Link from 'next/link'
|
|
6
|
-
import { usePathname } from 'next/navigation'
|
|
7
|
-
|
|
8
|
-
import { motion } from 'framer-motion'
|
|
9
|
-
|
|
10
|
-
import { buttonVariants } from '@/components/ui/button'
|
|
11
|
-
import { IconMessage, IconUsers } from '@/components/ui/icons'
|
|
12
|
-
import {
|
|
13
|
-
Tooltip,
|
|
14
|
-
TooltipContent,
|
|
15
|
-
TooltipTrigger
|
|
16
|
-
} from '@/components/ui/tooltip'
|
|
17
|
-
import { useLocalStorage } from '@/lib/hooks/use-local-storage'
|
|
18
|
-
import { type Chat } from '@/lib/types'
|
|
19
|
-
import { cn } from '@/lib/utils'
|
|
20
|
-
|
|
21
|
-
interface SidebarItemProps {
|
|
22
|
-
index: number
|
|
23
|
-
chat: Chat
|
|
24
|
-
children: React.ReactNode
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function SidebarItem({ index, chat, children }: SidebarItemProps) {
|
|
28
|
-
const pathname = usePathname()
|
|
29
|
-
|
|
30
|
-
const isActive = pathname === chat.path
|
|
31
|
-
const [newChatId, setNewChatId] = useLocalStorage('newChatId', null)
|
|
32
|
-
const shouldAnimate = index === 0 && isActive && newChatId
|
|
33
|
-
|
|
34
|
-
if (!chat?.id) return null
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<motion.div
|
|
38
|
-
className="relative h-8"
|
|
39
|
-
variants={{
|
|
40
|
-
initial: {
|
|
41
|
-
height: 0,
|
|
42
|
-
opacity: 0
|
|
43
|
-
},
|
|
44
|
-
animate: {
|
|
45
|
-
height: 'auto',
|
|
46
|
-
opacity: 1
|
|
47
|
-
}
|
|
48
|
-
}}
|
|
49
|
-
initial={shouldAnimate ? 'initial' : undefined}
|
|
50
|
-
animate={shouldAnimate ? 'animate' : undefined}
|
|
51
|
-
transition={{
|
|
52
|
-
duration: 0.25,
|
|
53
|
-
ease: 'easeIn'
|
|
54
|
-
}}
|
|
55
|
-
>
|
|
56
|
-
<div className="absolute left-2 top-1 flex size-6 items-center justify-center">
|
|
57
|
-
{chat.sharePath ? (
|
|
58
|
-
<Tooltip delayDuration={1000}>
|
|
59
|
-
<TooltipTrigger
|
|
60
|
-
tabIndex={-1}
|
|
61
|
-
className="focus:bg-muted focus:ring-1 focus:ring-ring"
|
|
62
|
-
>
|
|
63
|
-
<IconUsers className="mr-2 mt-1 text-zinc-500" />
|
|
64
|
-
</TooltipTrigger>
|
|
65
|
-
<TooltipContent>This is a shared chat.</TooltipContent>
|
|
66
|
-
</Tooltip>
|
|
67
|
-
) : (
|
|
68
|
-
<IconMessage className="mr-2 mt-1 text-zinc-500" />
|
|
69
|
-
)}
|
|
70
|
-
</div>
|
|
71
|
-
<Link
|
|
72
|
-
href={chat.path}
|
|
73
|
-
className={cn(
|
|
74
|
-
buttonVariants({ variant: 'ghost' }),
|
|
75
|
-
'group w-full px-8 transition-colors hover:bg-zinc-200/40 dark:hover:bg-zinc-300/10',
|
|
76
|
-
isActive && 'bg-zinc-200 pr-16 font-semibold dark:bg-zinc-800'
|
|
77
|
-
)}
|
|
78
|
-
>
|
|
79
|
-
<div
|
|
80
|
-
className="relative max-h-5 flex-1 select-none overflow-hidden text-ellipsis break-all"
|
|
81
|
-
title={chat.title}
|
|
82
|
-
>
|
|
83
|
-
<span className="whitespace-nowrap">
|
|
84
|
-
{shouldAnimate ? (
|
|
85
|
-
chat.title.split('').map((character, index) => (
|
|
86
|
-
<motion.span
|
|
87
|
-
key={index}
|
|
88
|
-
variants={{
|
|
89
|
-
initial: {
|
|
90
|
-
opacity: 0,
|
|
91
|
-
x: -100
|
|
92
|
-
},
|
|
93
|
-
animate: {
|
|
94
|
-
opacity: 1,
|
|
95
|
-
x: 0
|
|
96
|
-
}
|
|
97
|
-
}}
|
|
98
|
-
initial={shouldAnimate ? 'initial' : undefined}
|
|
99
|
-
animate={shouldAnimate ? 'animate' : undefined}
|
|
100
|
-
transition={{
|
|
101
|
-
duration: 0.25,
|
|
102
|
-
ease: 'easeIn',
|
|
103
|
-
delay: index * 0.05,
|
|
104
|
-
staggerChildren: 0.05
|
|
105
|
-
}}
|
|
106
|
-
onAnimationComplete={() => {
|
|
107
|
-
if (index === chat.title.length - 1) {
|
|
108
|
-
setNewChatId(null)
|
|
109
|
-
}
|
|
110
|
-
}}
|
|
111
|
-
>
|
|
112
|
-
{character}
|
|
113
|
-
</motion.span>
|
|
114
|
-
))
|
|
115
|
-
) : (
|
|
116
|
-
<span>{chat.title}</span>
|
|
117
|
-
)}
|
|
118
|
-
</span>
|
|
119
|
-
</div>
|
|
120
|
-
</Link>
|
|
121
|
-
{isActive && <div className="absolute right-2 top-1">{children}</div>}
|
|
122
|
-
</motion.div>
|
|
123
|
-
)
|
|
124
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { Chat } from '@/lib/types'
|
|
4
|
-
import { AnimatePresence, motion } from 'framer-motion'
|
|
5
|
-
|
|
6
|
-
import { removeChat, shareChat } from '@/app/actions'
|
|
7
|
-
|
|
8
|
-
import { SidebarActions } from '@/components/sidebar-actions'
|
|
9
|
-
import { SidebarItem } from '@/components/sidebar-item'
|
|
10
|
-
|
|
11
|
-
interface SidebarItemsProps {
|
|
12
|
-
chats?: Chat[]
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function SidebarItems({ chats }: SidebarItemsProps) {
|
|
16
|
-
if (!chats?.length) return null
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<AnimatePresence>
|
|
20
|
-
{chats.map(
|
|
21
|
-
(chat, index) =>
|
|
22
|
-
chat && (
|
|
23
|
-
<motion.div
|
|
24
|
-
key={chat?.id}
|
|
25
|
-
exit={{
|
|
26
|
-
opacity: 0,
|
|
27
|
-
height: 0
|
|
28
|
-
}}
|
|
29
|
-
>
|
|
30
|
-
<SidebarItem index={index} chat={chat}>
|
|
31
|
-
<SidebarActions
|
|
32
|
-
chat={chat}
|
|
33
|
-
removeChat={removeChat}
|
|
34
|
-
shareChat={shareChat}
|
|
35
|
-
/>
|
|
36
|
-
</SidebarItem>
|
|
37
|
-
</motion.div>
|
|
38
|
-
)
|
|
39
|
-
)}
|
|
40
|
-
</AnimatePresence>
|
|
41
|
-
)
|
|
42
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { clearChats, getChats } from '@/app/actions'
|
|
2
|
-
import { ClearHistory } from '@/components/clear-history'
|
|
3
|
-
import { SidebarItems } from '@/components/sidebar-items'
|
|
4
|
-
import { ThemeToggle } from '@/components/theme-toggle'
|
|
5
|
-
import { cache } from 'react'
|
|
6
|
-
|
|
7
|
-
interface SidebarListProps {
|
|
8
|
-
userId?: string
|
|
9
|
-
children?: React.ReactNode
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const loadChats = cache(async (userId?: string) => {
|
|
13
|
-
return await getChats(userId)
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
export async function SidebarList({ userId }: SidebarListProps) {
|
|
17
|
-
const chats = await loadChats(userId)
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<div className="flex flex-1 flex-col overflow-hidden">
|
|
21
|
-
<div className="flex-1 overflow-auto">
|
|
22
|
-
{chats?.length ? (
|
|
23
|
-
<div className="space-y-2 px-2">
|
|
24
|
-
<SidebarItems chats={chats} />
|
|
25
|
-
</div>
|
|
26
|
-
) : (
|
|
27
|
-
<div className="p-8 text-center">
|
|
28
|
-
<p className="text-sm text-muted-foreground">No chat history</p>
|
|
29
|
-
</div>
|
|
30
|
-
)}
|
|
31
|
-
</div>
|
|
32
|
-
<div className="flex items-center justify-between p-4">
|
|
33
|
-
<ThemeToggle />
|
|
34
|
-
<ClearHistory clearChats={clearChats} isEnabled={chats?.length > 0} />
|
|
35
|
-
</div>
|
|
36
|
-
</div>
|
|
37
|
-
)
|
|
38
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'
|
|
4
|
-
|
|
5
|
-
import { Sidebar } from '@/components/sidebar'
|
|
6
|
-
import { Button } from '@/components/ui/button'
|
|
7
|
-
|
|
8
|
-
import { IconSidebar } from '@/components/ui/icons'
|
|
9
|
-
|
|
10
|
-
interface SidebarMobileProps {
|
|
11
|
-
children: React.ReactNode
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function SidebarMobile({ children }: SidebarMobileProps) {
|
|
15
|
-
return (
|
|
16
|
-
<Sheet>
|
|
17
|
-
<SheetTrigger asChild>
|
|
18
|
-
<Button variant="ghost" className="-ml-2 flex size-9 p-0 lg:hidden">
|
|
19
|
-
<IconSidebar className="size-6" />
|
|
20
|
-
<span className="sr-only">Toggle Sidebar</span>
|
|
21
|
-
</Button>
|
|
22
|
-
</SheetTrigger>
|
|
23
|
-
<SheetContent
|
|
24
|
-
side="left"
|
|
25
|
-
className="inset-y-0 flex h-auto w-[300px] flex-col p-0"
|
|
26
|
-
>
|
|
27
|
-
<Sidebar className="flex">{children}</Sidebar>
|
|
28
|
-
</SheetContent>
|
|
29
|
-
</Sheet>
|
|
30
|
-
)
|
|
31
|
-
}
|