wuyiqunLu commited on
Commit
63d0776
1 Parent(s): 1b0e328

feat: parse new msg format (#57)

Browse files

log the data from vision agent, and set the message in client side to
have more flexibilities.



https://github.com/landing-ai/vision-agent-ui/assets/132986242/bd899636-2b36-49dc-abd1-287125d54f43


https://github.com/landing-ai/vision-agent-ui/assets/132986242/89c7474b-ce49-44a7-b1fc-fb53e1599408

app/api/vision-agent/route.ts CHANGED
@@ -10,46 +10,6 @@ import { cleanAnswerMessage, cleanInputMessage } from '@/lib/messageUtils';
10
  export const dynamic = 'force-dynamic';
11
  export const maxDuration = 300; // This function can run for a maximum of 5 minutes
12
 
13
- const parseLine = (line: string) => {
14
- try {
15
- const json = JSON.parse(line);
16
- let message = (json.log ?? '') + '\n';
17
- if (json.task || json.plan || json.reflection) {
18
- const arr = json.plan
19
- ? json.plan
20
- : json.task
21
- ? [json.task]
22
- : [json.reflection];
23
- const keys = Object.keys(arr[0]);
24
- message += '\n';
25
- message += '| ' + keys.join(' | ') + ' |' + '\n';
26
- message += new Array(keys.length + 1).fill('|').join(' :- ') + '\n';
27
- arr.forEach((obj: any) => {
28
- message += '| ' + keys.map(key => obj[key]).join(' | ') + ' |' + '\n';
29
- });
30
- message += '\n';
31
- }
32
- if (json.tools) {
33
- message += '\n';
34
- message += '| ' + 'Descriptions' + ' |' + '\n';
35
- message += '| ' + ':-' + ' |' + '\n';
36
- json.tools.forEach((tool: string) => {
37
- message += '| ' + tool + ' |' + '\n';
38
- });
39
- message += '\n';
40
- }
41
- if (json.code) {
42
- message += `\`\`\`python\n${json.code}\n\`\`\`\n`;
43
- }
44
- if (json.result) {
45
- message += `\`\`\`\n${json.result}\n\`\`\`\n`;
46
- }
47
- return { message };
48
- } catch (e) {
49
- return { error: e };
50
- }
51
- };
52
-
53
  export const POST = withLogging(
54
  async (
55
  session,
@@ -117,7 +77,7 @@ export const POST = withLogging(
117
  const { done, value } = await reader.read();
118
  if (!done) {
119
  const errorText = new TextDecoder().decode(value);
120
- logger.error(session, errorText, request);
121
  controller.error(new Error(`Response error: ${errorText}`));
122
  }
123
  } catch (e) {
@@ -135,7 +95,7 @@ export const POST = withLogging(
135
  start(controller) {
136
  logger.error(
137
  session,
138
- 'Response error: No response body',
139
  request,
140
  );
141
  controller.error(new Error('Response error: No response body'));
@@ -152,39 +112,24 @@ export const POST = withLogging(
152
  const encoder = new TextEncoder();
153
  const decoder = new TextDecoder('utf-8');
154
  let buffer = '';
 
155
  const stream = fetchResponse.body.pipeThrough(
156
  new TransformStream({
 
 
 
 
 
 
 
 
 
 
 
157
  transform: async (chunk, controller) => {
158
  const data = decoder.decode(chunk, { stream: true });
159
- buffer += data;
160
- let lines = buffer.split('\n');
161
- buffer = lines.pop() ?? ''; // Save the last incomplete line back to the buffer
162
- for (let line of lines) {
163
- if (!line.trim()) {
164
- continue;
165
- }
166
- if (line.trim()) {
167
- const { message, error } = parseLine(line.trim());
168
- if (message) {
169
- controller.enqueue(encoder.encode(message));
170
- } else if (error) {
171
- logger.error(
172
- session,
173
- { message: (error as Error).message, data },
174
- request,
175
- );
176
- controller.error(error);
177
- controller.terminate();
178
- }
179
- }
180
- }
181
- if (buffer.trim()) {
182
- const { message } = parseLine(buffer.trim());
183
- if (message) {
184
- buffer = '';
185
- controller.enqueue(encoder.encode(message));
186
- }
187
- }
188
  },
189
  }),
190
  );
 
10
  export const dynamic = 'force-dynamic';
11
  export const maxDuration = 300; // This function can run for a maximum of 5 minutes
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  export const POST = withLogging(
14
  async (
15
  session,
 
77
  const { done, value } = await reader.read();
78
  if (!done) {
79
  const errorText = new TextDecoder().decode(value);
80
+ logger.error(session, { message: errorText }, request);
81
  controller.error(new Error(`Response error: ${errorText}`));
82
  }
83
  } catch (e) {
 
95
  start(controller) {
96
  logger.error(
97
  session,
98
+ { message: 'Response error: No response body' },
99
  request,
100
  );
101
  controller.error(new Error('Response error: No response body'));
 
112
  const encoder = new TextEncoder();
113
  const decoder = new TextDecoder('utf-8');
114
  let buffer = '';
115
+ let maxChunkSize = 0;
116
  const stream = fetchResponse.body.pipeThrough(
117
  new TransformStream({
118
+ flush: () => {
119
+ logger.info(
120
+ session,
121
+ {
122
+ message: 'Streaming finished',
123
+ maxChunkSize,
124
+ },
125
+ request,
126
+ '__AGENT_DONE',
127
+ );
128
+ },
129
  transform: async (chunk, controller) => {
130
  const data = decoder.decode(chunk, { stream: true });
131
+ maxChunkSize = Math.max(data.length, maxChunkSize);
132
+ controller.enqueue(encoder.encode(data));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  },
134
  }),
135
  );
components/chat/ChatMessage.tsx CHANGED
@@ -3,8 +3,9 @@
3
 
4
  import remarkGfm from 'remark-gfm';
5
  import remarkMath from 'remark-math';
 
6
 
7
- import { useMemo } from 'react';
8
  import { cn } from '@/lib/utils';
9
  import { CodeBlock } from '@/components/ui/CodeBlock';
10
  import { MemoizedReactMarkdown } from '@/components/chat/MemoizedReactMarkdown';
@@ -18,12 +19,144 @@ import {
18
  import Img from '../ui/Img';
19
  import { getCleanedUpMessages } from '@/lib/messageUtils';
20
  import Loading from '../ui/Loading';
 
 
 
 
 
 
 
 
 
21
 
22
  export interface ChatMessageProps {
23
  message: MessageBase;
24
  isLoading: boolean;
25
  }
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  export function ChatMessage({
28
  message,
29
  isLoading,
@@ -35,6 +168,7 @@ export function ChatMessage({
35
  role: message.role,
36
  });
37
  }, [message.content, message.role]);
 
38
  return (
39
  <div className={cn('group relative mb-4 flex items-start')} {...props}>
40
  <div
@@ -48,98 +182,15 @@ export function ChatMessage({
48
  {message.role === 'user' ? <IconUser /> : <IconOpenAI />}
49
  </div>
50
  <div className="flex-1 px-1 ml-4 space-y-2 overflow-hidden">
51
- {logs && (
52
- <MemoizedReactMarkdown
53
- className="break-words"
54
- remarkPlugins={[remarkGfm, remarkMath]}
55
- components={{
56
- p({ children, ...props }) {
57
- if (
58
- props.node.children.some(
59
- child =>
60
- child.type === 'element' && child.tagName === 'img',
61
- )
62
- ) {
63
- return (
64
- <p className="flex flex-wrap gap-2 items-start">
65
- {children}
66
- </p>
67
- );
68
- }
69
- return (
70
- <p className="my-2 last:mb-0 whitespace-pre-line">
71
- {children}
72
- </p>
73
- );
74
- },
75
- img(props) {
76
- if (props.src?.endsWith('.mp4')) {
77
- return (
78
- <video src={props.src} controls width={500} height={500} />
79
- );
80
- }
81
- return (
82
- <Tooltip>
83
- <TooltipTrigger asChild>
84
- <Img
85
- src={props.src ?? '/landing.png'}
86
- alt={props.alt ?? 'answer-image'}
87
- quality={100}
88
- className="cursor-zoom-in"
89
- sizes="(min-width: 66em) 25vw,
90
- (min-width: 44em) 40vw,
91
- 100vw"
92
- />
93
- </TooltipTrigger>
94
- <TooltipContent>
95
- <Img
96
- className="m-2"
97
- src={props.src ?? '/landing.png'}
98
- alt={props.alt ?? 'answer-image'}
99
- quality={100}
100
- width={500}
101
- />
102
- </TooltipContent>
103
- </Tooltip>
104
- );
105
- },
106
- code({ node, inline, className, children, ...props }) {
107
- // if (children.length) {
108
- // if (children[0] == '▍') {
109
- // return (
110
- // <span className="mt-1 cursor-default animate-pulse">▍</span>
111
- // );
112
- // }
113
-
114
- // children[0] = (children[0] as string).replace('`▍`', '▍');
115
- // }
116
-
117
- const match = /language-(\w+)/.exec(className || '');
118
- // if (inline) {
119
- // return (
120
- // <code className={className} {...props}>
121
- // {children}
122
- // </code>
123
- // );
124
- // }
125
-
126
- return (
127
- <CodeBlock
128
- key={Math.random()}
129
- language={(match && match[1]) || ''}
130
- value={String(children).replace(/\n$/, '')}
131
- {...props}
132
- />
133
- );
134
- },
135
- }}
136
- >
137
- {logs}
138
- </MemoizedReactMarkdown>
139
- )}
140
  {/* <ChatMessageActions message={message} /> */}
141
  {isLoading && <Loading />}
142
  </div>
 
 
 
 
 
143
  </div>
144
  );
145
  }
 
3
 
4
  import remarkGfm from 'remark-gfm';
5
  import remarkMath from 'remark-math';
6
+ import rehypeRaw from 'rehype-raw';
7
 
8
+ import { useMemo, useState } from 'react';
9
  import { cn } from '@/lib/utils';
10
  import { CodeBlock } from '@/components/ui/CodeBlock';
11
  import { MemoizedReactMarkdown } from '@/components/chat/MemoizedReactMarkdown';
 
19
  import Img from '../ui/Img';
20
  import { getCleanedUpMessages } from '@/lib/messageUtils';
21
  import Loading from '../ui/Loading';
22
+ import {
23
+ Table,
24
+ TableCell,
25
+ TableHead,
26
+ TableHeader,
27
+ TableRow,
28
+ } from '../ui/Table';
29
+ import { Button } from '../ui/Button';
30
+ import { Dialog, DialogContent } from '../ui/Dialog';
31
 
32
  export interface ChatMessageProps {
33
  message: MessageBase;
34
  isLoading: boolean;
35
  }
36
 
37
+ const Markdown: React.FC<{
38
+ content: string;
39
+ setDetails?: (val: string) => void;
40
+ }> = ({ content, setDetails }) => {
41
+ return (
42
+ <>
43
+ <MemoizedReactMarkdown
44
+ className="break-words overflow-auto"
45
+ remarkPlugins={[remarkGfm, remarkMath]}
46
+ rehypePlugins={[rehypeRaw] as any}
47
+ components={{
48
+ table({ children, ...props }) {
49
+ return <Table {...props}>{children}</Table>;
50
+ },
51
+ thead({ children, ...props }) {
52
+ return <TableHeader {...props}>{children}</TableHeader>;
53
+ },
54
+ th({ children, ...props }) {
55
+ return <TableHead {...props}>{children}</TableHead>;
56
+ },
57
+ tr({ children, ...props }) {
58
+ return <TableRow {...props}>{children}</TableRow>;
59
+ },
60
+ td({ children, ...props }) {
61
+ return <TableCell {...props}>{children}</TableCell>;
62
+ },
63
+ button({ children, ...props }) {
64
+ if ('data-details' in props && setDetails) {
65
+ return (
66
+ <Button
67
+ {...props}
68
+ onClick={() =>
69
+ setDetails(decodeURI(props['data-details'] as string))
70
+ }
71
+ >
72
+ {children}
73
+ </Button>
74
+ );
75
+ }
76
+ return <Button {...props}>{children}</Button>;
77
+ },
78
+ p({ children, ...props }) {
79
+ if (
80
+ props.node.children.some(
81
+ child => child.type === 'element' && child.tagName === 'img',
82
+ )
83
+ ) {
84
+ return (
85
+ <p className="flex flex-wrap gap-2 items-start">{children}</p>
86
+ );
87
+ }
88
+ return (
89
+ <p className="my-2 last:mb-0 whitespace-pre-line">{children}</p>
90
+ );
91
+ },
92
+ img(props) {
93
+ if (props.src?.endsWith('.mp4')) {
94
+ return (
95
+ <video src={props.src} controls width={500} height={500} />
96
+ );
97
+ }
98
+ return (
99
+ <Tooltip>
100
+ <TooltipTrigger asChild>
101
+ <Img
102
+ src={props.src ?? '/landing.png'}
103
+ alt={props.alt ?? 'answer-image'}
104
+ quality={100}
105
+ className="cursor-zoom-in"
106
+ sizes="(min-width: 66em) 25vw,
107
+ (min-width: 44em) 40vw,
108
+ 100vw"
109
+ />
110
+ </TooltipTrigger>
111
+ <TooltipContent>
112
+ <Img
113
+ className="m-2"
114
+ src={props.src ?? '/landing.png'}
115
+ alt={props.alt ?? 'answer-image'}
116
+ quality={100}
117
+ width={500}
118
+ />
119
+ </TooltipContent>
120
+ </Tooltip>
121
+ );
122
+ },
123
+ code({ node, inline, className, children, ...props }) {
124
+ // if (children.length) {
125
+ // if (children[0] == '▍') {
126
+ // return (
127
+ // <span className="mt-1 cursor-default animate-pulse">▍</span>
128
+ // );
129
+ // }
130
+
131
+ // children[0] = (children[0] as string).replace('`▍`', '▍');
132
+ // }
133
+
134
+ const match = /language-(\w+)/.exec(className || '');
135
+ // if (inline) {
136
+ // return (
137
+ // <code className={className} {...props}>
138
+ // {children}
139
+ // </code>
140
+ // );
141
+ // }
142
+
143
+ return (
144
+ <CodeBlock
145
+ key={Math.random()}
146
+ language={(match && match[1]) || ''}
147
+ value={String(children).replace(/\n$/, '')}
148
+ {...props}
149
+ />
150
+ );
151
+ },
152
+ }}
153
+ >
154
+ {content}
155
+ </MemoizedReactMarkdown>
156
+ </>
157
+ );
158
+ };
159
+
160
  export function ChatMessage({
161
  message,
162
  isLoading,
 
168
  role: message.role,
169
  });
170
  }, [message.content, message.role]);
171
+ const [details, setDetails] = useState<string>('');
172
  return (
173
  <div className={cn('group relative mb-4 flex items-start')} {...props}>
174
  <div
 
182
  {message.role === 'user' ? <IconUser /> : <IconOpenAI />}
183
  </div>
184
  <div className="flex-1 px-1 ml-4 space-y-2 overflow-hidden">
185
+ {logs && <Markdown content={logs} setDetails={setDetails} />}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  {/* <ChatMessageActions message={message} /> */}
187
  {isLoading && <Loading />}
188
  </div>
189
+ <Dialog open={!!details} onOpenChange={open => !open && setDetails('')}>
190
+ <DialogContent className="w-11/12">
191
+ <Markdown content={details} />
192
+ </DialogContent>
193
+ </Dialog>
194
  </div>
195
  );
196
  }
components/ui/Dialog.tsx ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
5
+ import { X } from 'lucide-react';
6
+
7
+ import { cn } from '@/lib/utils';
8
+
9
+ const Dialog = DialogPrimitive.Root;
10
+
11
+ const DialogTrigger = DialogPrimitive.Trigger;
12
+
13
+ const DialogPortal = DialogPrimitive.Portal;
14
+
15
+ const DialogClose = DialogPrimitive.Close;
16
+
17
+ const DialogOverlay = React.forwardRef<
18
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
19
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
20
+ >(({ className, ...props }, ref) => (
21
+ <DialogPrimitive.Overlay
22
+ ref={ref}
23
+ className={cn(
24
+ 'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
25
+ className,
26
+ )}
27
+ {...props}
28
+ />
29
+ ));
30
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
31
+
32
+ const DialogContent = React.forwardRef<
33
+ React.ElementRef<typeof DialogPrimitive.Content>,
34
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
35
+ >(({ className, children, ...props }, ref) => (
36
+ <DialogPortal>
37
+ <DialogOverlay />
38
+ <DialogPrimitive.Content
39
+ ref={ref}
40
+ className={cn(
41
+ 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-3xl max-h-[85vh] overflow-y-auto translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
42
+ className,
43
+ )}
44
+ {...props}
45
+ >
46
+ {children}
47
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
48
+ <X className="h-4 w-4" />
49
+ <span className="sr-only">Close</span>
50
+ </DialogPrimitive.Close>
51
+ </DialogPrimitive.Content>
52
+ </DialogPortal>
53
+ ));
54
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
55
+
56
+ const DialogHeader = ({
57
+ className,
58
+ ...props
59
+ }: React.HTMLAttributes<HTMLDivElement>) => (
60
+ <div
61
+ className={cn(
62
+ 'flex flex-col space-y-1.5 text-center sm:text-left',
63
+ className,
64
+ )}
65
+ {...props}
66
+ />
67
+ );
68
+ DialogHeader.displayName = 'DialogHeader';
69
+
70
+ const DialogFooter = ({
71
+ className,
72
+ ...props
73
+ }: React.HTMLAttributes<HTMLDivElement>) => (
74
+ <div
75
+ className={cn(
76
+ 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
77
+ className,
78
+ )}
79
+ {...props}
80
+ />
81
+ );
82
+ DialogFooter.displayName = 'DialogFooter';
83
+
84
+ const DialogTitle = React.forwardRef<
85
+ React.ElementRef<typeof DialogPrimitive.Title>,
86
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
87
+ >(({ className, ...props }, ref) => (
88
+ <DialogPrimitive.Title
89
+ ref={ref}
90
+ className={cn(
91
+ 'text-lg font-semibold leading-none tracking-tight',
92
+ className,
93
+ )}
94
+ {...props}
95
+ />
96
+ ));
97
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
98
+
99
+ const DialogDescription = React.forwardRef<
100
+ React.ElementRef<typeof DialogPrimitive.Description>,
101
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
102
+ >(({ className, ...props }, ref) => (
103
+ <DialogPrimitive.Description
104
+ ref={ref}
105
+ className={cn('text-sm text-muted-foreground', className)}
106
+ {...props}
107
+ />
108
+ ));
109
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
110
+
111
+ export {
112
+ Dialog,
113
+ DialogPortal,
114
+ DialogOverlay,
115
+ DialogClose,
116
+ DialogTrigger,
117
+ DialogContent,
118
+ DialogHeader,
119
+ DialogFooter,
120
+ DialogTitle,
121
+ DialogDescription,
122
+ };
components/ui/Table.tsx ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as React from 'react';
2
+
3
+ import { cn } from '@/lib/utils';
4
+
5
+ const Table = React.forwardRef<
6
+ HTMLTableElement,
7
+ React.HTMLAttributes<HTMLTableElement>
8
+ >(({ className, ...props }, ref) => (
9
+ <div className="relative w-full overflow-auto">
10
+ <table
11
+ ref={ref}
12
+ className={cn('w-full caption-bottom text-sm', className)}
13
+ {...props}
14
+ />
15
+ </div>
16
+ ));
17
+ Table.displayName = 'Table';
18
+
19
+ const TableHeader = React.forwardRef<
20
+ HTMLTableSectionElement,
21
+ React.HTMLAttributes<HTMLTableSectionElement>
22
+ >(({ className, ...props }, ref) => (
23
+ <thead ref={ref} className={cn('[&_tr]:border-b', className)} {...props} />
24
+ ));
25
+ TableHeader.displayName = 'TableHeader';
26
+
27
+ const TableBody = React.forwardRef<
28
+ HTMLTableSectionElement,
29
+ React.HTMLAttributes<HTMLTableSectionElement>
30
+ >(({ className, ...props }, ref) => (
31
+ <tbody
32
+ ref={ref}
33
+ className={cn('[&_tr:last-child]:border-0', className)}
34
+ {...props}
35
+ />
36
+ ));
37
+ TableBody.displayName = 'TableBody';
38
+
39
+ const TableFooter = React.forwardRef<
40
+ HTMLTableSectionElement,
41
+ React.HTMLAttributes<HTMLTableSectionElement>
42
+ >(({ className, ...props }, ref) => (
43
+ <tfoot
44
+ ref={ref}
45
+ className={cn(
46
+ 'border-t bg-muted/50 font-medium [&>tr]:last:border-b-0',
47
+ className,
48
+ )}
49
+ {...props}
50
+ />
51
+ ));
52
+ TableFooter.displayName = 'TableFooter';
53
+
54
+ const TableRow = React.forwardRef<
55
+ HTMLTableRowElement,
56
+ React.HTMLAttributes<HTMLTableRowElement>
57
+ >(({ className, ...props }, ref) => (
58
+ <tr
59
+ ref={ref}
60
+ className={cn(
61
+ 'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
62
+ className,
63
+ )}
64
+ {...props}
65
+ />
66
+ ));
67
+ TableRow.displayName = 'TableRow';
68
+
69
+ const TableHead = React.forwardRef<
70
+ HTMLTableCellElement,
71
+ React.ThHTMLAttributes<HTMLTableCellElement>
72
+ >(({ className, ...props }, ref) => (
73
+ <th
74
+ ref={ref}
75
+ className={cn(
76
+ 'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
77
+ className,
78
+ )}
79
+ {...props}
80
+ />
81
+ ));
82
+ TableHead.displayName = 'TableHead';
83
+
84
+ const TableCell = React.forwardRef<
85
+ HTMLTableCellElement,
86
+ React.TdHTMLAttributes<HTMLTableCellElement>
87
+ >(({ className, ...props }, ref) => (
88
+ <td
89
+ ref={ref}
90
+ className={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)}
91
+ {...props}
92
+ />
93
+ ));
94
+ TableCell.displayName = 'TableCell';
95
+
96
+ const TableCaption = React.forwardRef<
97
+ HTMLTableCaptionElement,
98
+ React.HTMLAttributes<HTMLTableCaptionElement>
99
+ >(({ className, ...props }, ref) => (
100
+ <caption
101
+ ref={ref}
102
+ className={cn('mt-4 text-sm text-muted-foreground', className)}
103
+ {...props}
104
+ />
105
+ ));
106
+ TableCaption.displayName = 'TableCaption';
107
+
108
+ export {
109
+ Table,
110
+ TableHeader,
111
+ TableBody,
112
+ TableFooter,
113
+ TableHead,
114
+ TableRow,
115
+ TableCell,
116
+ TableCaption,
117
+ };
lib/messageUtils.ts CHANGED
@@ -38,10 +38,250 @@ export const cleanAnswerMessage = (content: string) => {
38
  return content.replace(/!\[answers.*?\.png\)/g, '');
39
  };
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  export const getCleanedUpMessages = ({
42
  content,
43
  role,
44
  }: Pick<MessageBase, 'role' | 'content'>) => {
 
 
 
 
 
45
  if (content.split(CLEANED_SEPARATOR).length === 2) {
46
  return {
47
  logs: content.split(CLEANED_SEPARATOR)[0],
@@ -49,39 +289,30 @@ export const getCleanedUpMessages = ({
49
  };
50
  }
51
  const [logs = '', answer = ''] = content.split('<ANSWER>');
52
- // console.log(logs);
53
- // const cleanedLogs = [];
54
- // let left = 0;
55
- // let right = 0;
56
- // while (right < logs.length) {
57
- // if (Object.keys(PAIRS).includes(content[right])) {
58
- // cleanedLogs.push(content.substring(left, right));
59
- // left = right++;
60
- // while (
61
- // right < content.length &&
62
- // PAIRS[content[left]] !== content[right]
63
- // ) {
64
- // right++;
65
- // }
66
- // if (content[left] === MIDDLE_STARTER) {
67
- // // add the text alignment so it can be shown as a table
68
- // const separators = logs
69
- // .substring(left, right)
70
- // .split(MIDDLE_SEPARATOR).length;
71
- // if (separators > 0) {
72
- // cleanedLogs.push(
73
- // Array(separators + 1)
74
- // .fill('|')
75
- // .join(' :- '),
76
- // );
77
- // }
78
- // }
79
- // left = ++right;
80
- // } else {
81
- // right++;
82
- // }
83
- // }
84
- // cleanedLogs.push(content.substring(left, right));
85
  const [answerText, imagesStr = ''] = answer.split('<VIZ>');
86
  const [imagesArrayStr, ...rest] = imagesStr.split('</VIZ>');
87
  const images = imagesArrayStr
@@ -89,7 +320,7 @@ export const getCleanedUpMessages = ({
89
  .map(str => str.replace('<IMG>', ''))
90
  .slice(0, -1);
91
  return {
92
- logs: logs,
93
  content:
94
  answerText.replace('</</ANSWER>', '').replace('</ANSWER>', '') +
95
  '\n\n' +
 
38
  return content.replace(/!\[answers.*?\.png\)/g, '');
39
  };
40
 
41
+ const generateJSONArrayMarkdown = (
42
+ message: string,
43
+ payload: Array<Record<string, string | boolean>>,
44
+ ) => {
45
+ if (payload.length === 0) return '';
46
+ const keys = Object.keys(payload[0]);
47
+ message += '\n';
48
+ message += '| ' + keys.join(' | ') + ' |' + '\n';
49
+ message += new Array(keys.length + 1).fill('|').join(' :- ') + '\n';
50
+ payload.forEach((obj: any) => {
51
+ message +=
52
+ '| ' +
53
+ keys
54
+ .map(key => {
55
+ if (key === 'documentation') {
56
+ const doc = `\`\`\`\n${obj[key]}\n\`\`\`\n`;
57
+ return `<button data-details=${JSON.stringify(encodeURI(doc))}>Show</button>`;
58
+ } else {
59
+ return obj[key];
60
+ }
61
+ })
62
+ .join(' | ') +
63
+ ' |' +
64
+ '\n';
65
+ });
66
+ message += '\n';
67
+ return message;
68
+ };
69
+
70
+ const generateStringArrayMarkdown = (
71
+ message: string,
72
+ header: string,
73
+ payload: Array<string>,
74
+ ) => {
75
+ message += '\n';
76
+ message += '| ' + header + ' |' + '\n';
77
+ message += '| ' + ':-' + ' |' + '\n';
78
+ payload.forEach((tool: string) => {
79
+ message += '| ' + tool + ' |' + '\n';
80
+ });
81
+ message += '\n';
82
+ return message;
83
+ };
84
+
85
+ const generateCodeExecutionMarkdown = (
86
+ message: string,
87
+ payload: {
88
+ code: string;
89
+ test: string;
90
+ result?: string;
91
+ },
92
+ ) => {
93
+ let Details = 'Code: \n';
94
+ Details += `\`\`\`python\n${payload.code}\n\`\`\`\n`;
95
+ Details += 'Test: \n';
96
+ Details += `\`\`\`python\n${payload.test}\n\`\`\`\n`;
97
+ if (payload.result) {
98
+ Details += 'Execution result: \n';
99
+ Details += `\`\`\`python\n${payload.result}\n\`\`\`\n`;
100
+ }
101
+ message += `<button data-details=${JSON.stringify(encodeURI(Details))}>View details</button> \n`;
102
+
103
+ return message;
104
+ };
105
+
106
+ const generateFinalCodeMarkdown = (
107
+ message: string,
108
+ payload: {
109
+ code: string;
110
+ test: string;
111
+ result: string;
112
+ },
113
+ ) => {
114
+ message += 'Final Code: \n';
115
+ message += `\`\`\`python\n${payload.code}\n\`\`\`\n`;
116
+ message += 'Final test: \n';
117
+ message += `\`\`\`python\n${payload.test}\n\`\`\`\n`;
118
+ message += `Final result: \n`;
119
+ message += `\`\`\`\n${payload.result}\n\`\`\`\n`;
120
+ return message;
121
+ };
122
+
123
+ const generateFinalResultMarkdown = (
124
+ message: string,
125
+ payload: {
126
+ success: boolean;
127
+ reach_max_retries: boolean;
128
+ },
129
+ ) => {
130
+ if (payload.reach_max_retries) {
131
+ message += 'Reach max debug retries!\n';
132
+ } else if (payload.success) {
133
+ message += 'Success!';
134
+ }
135
+ message += '\n';
136
+ return message;
137
+ };
138
+
139
+ type PlansBody =
140
+ | {
141
+ type: 'plans';
142
+ status: 'started';
143
+ }
144
+ | {
145
+ type: 'plans';
146
+ status: 'completed';
147
+ payload: Array<Record<string, string>>;
148
+ };
149
+
150
+ type ToolsBody =
151
+ | {
152
+ type: 'tools';
153
+ status: 'started';
154
+ }
155
+ | {
156
+ type: 'tools';
157
+ status: 'completed';
158
+ payload: Array<Record<string, string>>;
159
+ };
160
+
161
+ type CodeBody =
162
+ | {
163
+ type: 'code';
164
+ status: 'started';
165
+ }
166
+ | {
167
+ type: 'code';
168
+ status: 'running';
169
+ payload: {
170
+ code: string;
171
+ test: string;
172
+ };
173
+ }
174
+ | {
175
+ type: 'code';
176
+ status: 'completed' | 'failed';
177
+ payload: {
178
+ code: string;
179
+ test: string;
180
+ result: string;
181
+ };
182
+ };
183
+
184
+ type FinalCodeBody = {
185
+ type: 'final_code';
186
+ status: 'completed' | 'failed';
187
+ payload: {
188
+ code: string;
189
+ test: string;
190
+ result: string;
191
+ };
192
+ };
193
+
194
+ // this will return if self_reflection flag is true
195
+ type ReflectionBody =
196
+ | {
197
+ type: 'self_reflection';
198
+ status: 'started';
199
+ }
200
+ | {
201
+ type: 'self_reflection';
202
+ status: 'completed' | 'failed';
203
+ payload: { feedback: string; success: boolean };
204
+ };
205
+
206
+ type MessageBody =
207
+ | PlansBody
208
+ | ToolsBody
209
+ | CodeBody
210
+ | ReflectionBody
211
+ | FinalCodeBody;
212
+
213
+ const getMessageTitle = (json: MessageBody) => {
214
+ switch (json.type) {
215
+ case 'plans':
216
+ if (json.status === 'started') {
217
+ return '🎬 Start generating plans...\n';
218
+ } else {
219
+ return '✅ Going to run the following plan(s) in sequence:\n';
220
+ }
221
+ case 'tools':
222
+ if (json.status === 'started') {
223
+ return '🎬 Start retrieving tools...\n';
224
+ } else {
225
+ return '✅ Tools retrieved:\n';
226
+ }
227
+ case 'code':
228
+ if (json.status === 'started') {
229
+ return '🎬 Start generating code...\n';
230
+ } else if (json.status === 'running') {
231
+ return '🎬 Code generated, start execution... ';
232
+ } else if (json.status === 'completed') {
233
+ return '✅ Code executed successfully. ';
234
+ } else {
235
+ return '❌ Code execution failed. ';
236
+ }
237
+ case 'self_reflection':
238
+ if (json.status === 'started') {
239
+ return '🎬 Start self reflection...\n';
240
+ } else if (json.status === 'completed') {
241
+ return '✅ Self reflection completed: \n';
242
+ } else {
243
+ return '❌ Self reflection failed: \n';
244
+ }
245
+ case 'final_code':
246
+ if (json.status === 'completed') {
247
+ return '✅ The vision agent has concluded the chat, the last execution is successful. \n';
248
+ } else {
249
+ return '❌ he vision agent has concluded the chat, the last execution is failed. \n';
250
+ }
251
+ default:
252
+ throw 'Not supported type';
253
+ }
254
+ };
255
+ const parseLine = (json: MessageBody) => {
256
+ const title = getMessageTitle(json);
257
+ if (json.status === 'started') {
258
+ return title;
259
+ }
260
+ switch (json.type) {
261
+ case 'plans':
262
+ return generateJSONArrayMarkdown(title, json.payload);
263
+ case 'tools':
264
+ return generateJSONArrayMarkdown(title, json.payload);
265
+ case 'code':
266
+ return generateCodeExecutionMarkdown(title, json.payload);
267
+ case 'self_reflection':
268
+ return generateJSONArrayMarkdown(title, [json.payload]);
269
+ case 'final_code':
270
+ return generateFinalCodeMarkdown(title, json.payload);
271
+ default:
272
+ throw 'Not supported type';
273
+ }
274
+ };
275
+
276
  export const getCleanedUpMessages = ({
277
  content,
278
  role,
279
  }: Pick<MessageBase, 'role' | 'content'>) => {
280
+ if (role === 'user') {
281
+ return {
282
+ logs: content,
283
+ };
284
+ }
285
  if (content.split(CLEANED_SEPARATOR).length === 2) {
286
  return {
287
  logs: content.split(CLEANED_SEPARATOR)[0],
 
289
  };
290
  }
291
  const [logs = '', answer = ''] = content.split('<ANSWER>');
292
+ const lines = logs.split('\n');
293
+ let formattedLogs = '';
294
+ const jsons: MessageBody[] = [];
295
+ for (let line of lines) {
296
+ if (!line.trim()) {
297
+ continue;
298
+ }
299
+ try {
300
+ const json = JSON.parse(line) as MessageBody;
301
+ if (
302
+ jsons.length > 0 &&
303
+ json.type === jsons[jsons.length - 1].type &&
304
+ json.status !== 'started'
305
+ ) {
306
+ jsons[jsons.length - 1] = json;
307
+ } else {
308
+ jsons.push(json);
309
+ }
310
+ } catch (e) {
311
+ console.error((e as Error).message);
312
+ console.error(line);
313
+ }
314
+ }
315
+ jsons.forEach(json => (formattedLogs += parseLine(json)));
 
 
 
 
 
 
 
 
 
316
  const [answerText, imagesStr = ''] = answer.split('<VIZ>');
317
  const [imagesArrayStr, ...rest] = imagesStr.split('</VIZ>');
318
  const images = imagesArrayStr
 
320
  .map(str => str.replace('<IMG>', ''))
321
  .slice(0, -1);
322
  return {
323
+ logs: formattedLogs,
324
  content:
325
  answerText.replace('</</ANSWER>', '').replace('</ANSWER>', '') +
326
  '\n\n' +
package.json CHANGED
@@ -18,6 +18,7 @@
18
  "@aws-sdk/credential-providers": "^3.556.0",
19
  "@aws-sdk/s3-presigned-post": "^3.556.0",
20
  "@prisma/client": "5.14.0",
 
21
  "@radix-ui/react-dropdown-menu": "^2.0.6",
22
  "@radix-ui/react-icons": "^1.3.0",
23
  "@radix-ui/react-separator": "^1.0.3",
@@ -54,6 +55,7 @@
54
  "react-textarea-autosize": "^8.5.3",
55
  "react-virtualized-auto-sizer": "^1.0.24",
56
  "react-window": "^1.8.10",
 
57
  "remark-gfm": "^3.0.1",
58
  "remark-math": "^5.1.1",
59
  "sharp": "^0.33.3",
 
18
  "@aws-sdk/credential-providers": "^3.556.0",
19
  "@aws-sdk/s3-presigned-post": "^3.556.0",
20
  "@prisma/client": "5.14.0",
21
+ "@radix-ui/react-dialog": "^1.0.5",
22
  "@radix-ui/react-dropdown-menu": "^2.0.6",
23
  "@radix-ui/react-icons": "^1.3.0",
24
  "@radix-ui/react-separator": "^1.0.3",
 
55
  "react-textarea-autosize": "^8.5.3",
56
  "react-virtualized-auto-sizer": "^1.0.24",
57
  "react-window": "^1.8.10",
58
+ "rehype-raw": "^7.0.0",
59
  "remark-gfm": "^3.0.1",
60
  "remark-math": "^5.1.1",
61
  "sharp": "^0.33.3",
pnpm-lock.yaml CHANGED
@@ -20,6 +20,9 @@ importers:
20
  '@prisma/client':
21
  specifier: 5.14.0
22
  version: 5.14.0(prisma@5.14.0)
 
 
 
23
  '@radix-ui/react-dropdown-menu':
24
  specifier: ^2.0.6
25
  version: 2.0.6(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -128,6 +131,9 @@ importers:
128
  react-window:
129
  specifier: ^1.8.10
130
  version: 1.8.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
 
 
 
131
  remark-gfm:
132
  specifier: ^3.0.1
133
  version: 3.0.1
@@ -773,6 +779,19 @@ packages:
773
  '@types/react':
774
  optional: true
775
 
 
 
 
 
 
 
 
 
 
 
 
 
 
776
  '@radix-ui/react-direction@1.0.1':
777
  resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==}
778
  peerDependencies:
@@ -1277,6 +1296,9 @@ packages:
1277
  '@types/hast@2.3.10':
1278
  resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==}
1279
 
 
 
 
1280
  '@types/http-cache-semantics@4.0.4':
1281
  resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
1282
 
@@ -1292,6 +1314,9 @@ packages:
1292
  '@types/mdast@3.0.15':
1293
  resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==}
1294
 
 
 
 
1295
  '@types/ms@0.7.34':
1296
  resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
1297
 
@@ -1325,6 +1350,9 @@ packages:
1325
  '@types/unist@2.0.10':
1326
  resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
1327
 
 
 
 
1328
  '@types/uuid@9.0.8':
1329
  resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
1330
 
@@ -1784,6 +1812,9 @@ packages:
1784
  detect-node-es@1.1.0:
1785
  resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
1786
 
 
 
 
1787
  didyoumean@1.2.2:
1788
  resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
1789
 
@@ -2221,18 +2252,36 @@ packages:
2221
  resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
2222
  engines: {node: '>= 0.4'}
2223
 
 
 
 
2224
  hast-util-parse-selector@2.2.5:
2225
  resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==}
2226
 
 
 
 
 
 
 
 
 
 
2227
  hast-util-whitespace@2.0.1:
2228
  resolution: {integrity: sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==}
2229
 
2230
  hastscript@6.0.0:
2231
  resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==}
2232
 
 
 
 
2233
  highlight.js@10.7.3:
2234
  resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
2235
 
 
 
 
2236
  http-cache-semantics@4.1.1:
2237
  resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
2238
 
@@ -2585,6 +2634,9 @@ packages:
2585
  mdast-util-to-hast@12.3.0:
2586
  resolution: {integrity: sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==}
2587
 
 
 
 
2588
  mdast-util-to-markdown@1.5.0:
2589
  resolution: {integrity: sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==}
2590
 
@@ -2646,6 +2698,9 @@ packages:
2646
  micromark-util-character@1.2.0:
2647
  resolution: {integrity: sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==}
2648
 
 
 
 
2649
  micromark-util-chunked@1.1.0:
2650
  resolution: {integrity: sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==}
2651
 
@@ -2664,6 +2719,9 @@ packages:
2664
  micromark-util-encode@1.1.0:
2665
  resolution: {integrity: sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==}
2666
 
 
 
 
2667
  micromark-util-html-tag-name@1.2.0:
2668
  resolution: {integrity: sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==}
2669
 
@@ -2676,15 +2734,24 @@ packages:
2676
  micromark-util-sanitize-uri@1.2.0:
2677
  resolution: {integrity: sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==}
2678
 
 
 
 
2679
  micromark-util-subtokenize@1.1.0:
2680
  resolution: {integrity: sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==}
2681
 
2682
  micromark-util-symbol@1.1.0:
2683
  resolution: {integrity: sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==}
2684
 
 
 
 
2685
  micromark-util-types@1.1.0:
2686
  resolution: {integrity: sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==}
2687
 
 
 
 
2688
  micromark@3.2.0:
2689
  resolution: {integrity: sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==}
2690
 
@@ -2899,6 +2966,9 @@ packages:
2899
  parse-entities@2.0.0:
2900
  resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==}
2901
 
 
 
 
2902
  path-exists@4.0.0:
2903
  resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
2904
  engines: {node: '>=8'}
@@ -3199,6 +3269,9 @@ packages:
3199
  resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
3200
  engines: {node: '>= 0.4'}
3201
 
 
 
 
3202
  remark-gfm@3.0.1:
3203
  resolution: {integrity: sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==}
3204
 
@@ -3562,18 +3635,33 @@ packages:
3562
  unist-util-is@5.2.1:
3563
  resolution: {integrity: sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==}
3564
 
 
 
 
3565
  unist-util-position@4.0.4:
3566
  resolution: {integrity: sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==}
3567
 
 
 
 
3568
  unist-util-stringify-position@3.0.3:
3569
  resolution: {integrity: sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==}
3570
 
 
 
 
3571
  unist-util-visit-parents@5.1.3:
3572
  resolution: {integrity: sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==}
3573
 
 
 
 
3574
  unist-util-visit@4.1.2:
3575
  resolution: {integrity: sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==}
3576
 
 
 
 
3577
  update-browserslist-db@1.0.13:
3578
  resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
3579
  hasBin: true
@@ -3643,12 +3731,21 @@ packages:
3643
  engines: {node: '>=8'}
3644
  hasBin: true
3645
 
 
 
 
3646
  vfile-message@3.1.4:
3647
  resolution: {integrity: sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==}
3648
 
 
 
 
3649
  vfile@5.3.7:
3650
  resolution: {integrity: sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==}
3651
 
 
 
 
3652
  vue@3.4.23:
3653
  resolution: {integrity: sha512-X1y6yyGJ28LMUBJ0k/qIeKHstGd+BlWQEOT40x3auJFTmpIhpbKLgN7EFsqalnJXq1Km5ybDEsp6BhuWKciUDg==}
3654
  peerDependencies:
@@ -3657,6 +3754,9 @@ packages:
3657
  typescript:
3658
  optional: true
3659
 
 
 
 
3660
  web-streams-polyfill@3.3.3:
3661
  resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
3662
  engines: {node: '>= 8'}
@@ -4644,6 +4744,29 @@ snapshots:
4644
  optionalDependencies:
4645
  '@types/react': 18.2.79
4646
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4647
  '@radix-ui/react-direction@1.0.1(@types/react@18.2.79)(react@18.2.0)':
4648
  dependencies:
4649
  '@babel/runtime': 7.24.4
@@ -5284,6 +5407,10 @@ snapshots:
5284
  dependencies:
5285
  '@types/unist': 2.0.10
5286
 
 
 
 
 
5287
  '@types/http-cache-semantics@4.0.4': {}
5288
 
5289
  '@types/json5@0.0.29': {}
@@ -5298,6 +5425,10 @@ snapshots:
5298
  dependencies:
5299
  '@types/unist': 2.0.10
5300
 
 
 
 
 
5301
  '@types/ms@0.7.34': {}
5302
 
5303
  '@types/node-fetch@2.6.11':
@@ -5338,6 +5469,8 @@ snapshots:
5338
 
5339
  '@types/unist@2.0.10': {}
5340
 
 
 
5341
  '@types/uuid@9.0.8': {}
5342
 
5343
  '@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5)':
@@ -5841,6 +5974,10 @@ snapshots:
5841
 
5842
  detect-node-es@1.1.0: {}
5843
 
 
 
 
 
5844
  didyoumean@1.2.2: {}
5845
 
5846
  diff@5.2.0: {}
@@ -6434,8 +6571,49 @@ snapshots:
6434
  dependencies:
6435
  function-bind: 1.1.2
6436
 
 
 
 
 
 
 
 
 
 
 
 
6437
  hast-util-parse-selector@2.2.5: {}
6438
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6439
  hast-util-whitespace@2.0.1: {}
6440
 
6441
  hastscript@6.0.0:
@@ -6446,8 +6624,18 @@ snapshots:
6446
  property-information: 5.6.0
6447
  space-separated-tokens: 1.1.5
6448
 
 
 
 
 
 
 
 
 
6449
  highlight.js@10.7.3: {}
6450
 
 
 
6451
  http-cache-semantics@4.1.1: {}
6452
 
6453
  http2-wrapper@1.0.3:
@@ -6824,6 +7012,18 @@ snapshots:
6824
  unist-util-position: 4.0.4
6825
  unist-util-visit: 4.1.2
6826
 
 
 
 
 
 
 
 
 
 
 
 
 
6827
  mdast-util-to-markdown@1.5.0:
6828
  dependencies:
6829
  '@types/mdast': 3.0.15
@@ -6969,6 +7169,11 @@ snapshots:
6969
  micromark-util-symbol: 1.1.0
6970
  micromark-util-types: 1.1.0
6971
 
 
 
 
 
 
6972
  micromark-util-chunked@1.1.0:
6973
  dependencies:
6974
  micromark-util-symbol: 1.1.0
@@ -6997,6 +7202,8 @@ snapshots:
6997
 
6998
  micromark-util-encode@1.1.0: {}
6999
 
 
 
7000
  micromark-util-html-tag-name@1.2.0: {}
7001
 
7002
  micromark-util-normalize-identifier@1.1.0:
@@ -7013,6 +7220,12 @@ snapshots:
7013
  micromark-util-encode: 1.1.0
7014
  micromark-util-symbol: 1.1.0
7015
 
 
 
 
 
 
 
7016
  micromark-util-subtokenize@1.1.0:
7017
  dependencies:
7018
  micromark-util-chunked: 1.1.0
@@ -7022,8 +7235,12 @@ snapshots:
7022
 
7023
  micromark-util-symbol@1.1.0: {}
7024
 
 
 
7025
  micromark-util-types@1.1.0: {}
7026
 
 
 
7027
  micromark@3.2.0:
7028
  dependencies:
7029
  '@types/debug': 4.1.12
@@ -7247,6 +7464,10 @@ snapshots:
7247
  is-decimal: 1.0.4
7248
  is-hexadecimal: 1.0.4
7249
 
 
 
 
 
7250
  path-exists@4.0.0: {}
7251
 
7252
  path-is-absolute@1.0.1: {}
@@ -7562,6 +7783,12 @@ snapshots:
7562
  es-errors: 1.3.0
7563
  set-function-name: 2.0.2
7564
 
 
 
 
 
 
 
7565
  remark-gfm@3.0.1:
7566
  dependencies:
7567
  '@types/mdast': 3.0.15
@@ -8023,25 +8250,48 @@ snapshots:
8023
  dependencies:
8024
  '@types/unist': 2.0.10
8025
 
 
 
 
 
8026
  unist-util-position@4.0.4:
8027
  dependencies:
8028
  '@types/unist': 2.0.10
8029
 
 
 
 
 
8030
  unist-util-stringify-position@3.0.3:
8031
  dependencies:
8032
  '@types/unist': 2.0.10
8033
 
 
 
 
 
8034
  unist-util-visit-parents@5.1.3:
8035
  dependencies:
8036
  '@types/unist': 2.0.10
8037
  unist-util-is: 5.2.1
8038
 
 
 
 
 
 
8039
  unist-util-visit@4.1.2:
8040
  dependencies:
8041
  '@types/unist': 2.0.10
8042
  unist-util-is: 5.2.1
8043
  unist-util-visit-parents: 5.1.3
8044
 
 
 
 
 
 
 
8045
  update-browserslist-db@1.0.13(browserslist@4.23.0):
8046
  dependencies:
8047
  browserslist: 4.23.0
@@ -8099,11 +8349,21 @@ snapshots:
8099
  kleur: 4.1.5
8100
  sade: 1.8.1
8101
 
 
 
 
 
 
8102
  vfile-message@3.1.4:
8103
  dependencies:
8104
  '@types/unist': 2.0.10
8105
  unist-util-stringify-position: 3.0.3
8106
 
 
 
 
 
 
8107
  vfile@5.3.7:
8108
  dependencies:
8109
  '@types/unist': 2.0.10
@@ -8111,6 +8371,12 @@ snapshots:
8111
  unist-util-stringify-position: 3.0.3
8112
  vfile-message: 3.1.4
8113
 
 
 
 
 
 
 
8114
  vue@3.4.23(typescript@5.4.5):
8115
  dependencies:
8116
  '@vue/compiler-dom': 3.4.23
@@ -8121,6 +8387,8 @@ snapshots:
8121
  optionalDependencies:
8122
  typescript: 5.4.5
8123
 
 
 
8124
  web-streams-polyfill@3.3.3: {}
8125
 
8126
  web-streams-polyfill@4.0.0-beta.3: {}
 
20
  '@prisma/client':
21
  specifier: 5.14.0
22
  version: 5.14.0(prisma@5.14.0)
23
+ '@radix-ui/react-dialog':
24
+ specifier: ^1.0.5
25
+ version: 1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
26
  '@radix-ui/react-dropdown-menu':
27
  specifier: ^2.0.6
28
  version: 2.0.6(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
 
131
  react-window:
132
  specifier: ^1.8.10
133
  version: 1.8.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
134
+ rehype-raw:
135
+ specifier: ^7.0.0
136
+ version: 7.0.0
137
  remark-gfm:
138
  specifier: ^3.0.1
139
  version: 3.0.1
 
779
  '@types/react':
780
  optional: true
781
 
782
+ '@radix-ui/react-dialog@1.0.5':
783
+ resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==}
784
+ peerDependencies:
785
+ '@types/react': '*'
786
+ '@types/react-dom': '*'
787
+ react: ^16.8 || ^17.0 || ^18.0
788
+ react-dom: ^16.8 || ^17.0 || ^18.0
789
+ peerDependenciesMeta:
790
+ '@types/react':
791
+ optional: true
792
+ '@types/react-dom':
793
+ optional: true
794
+
795
  '@radix-ui/react-direction@1.0.1':
796
  resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==}
797
  peerDependencies:
 
1296
  '@types/hast@2.3.10':
1297
  resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==}
1298
 
1299
+ '@types/hast@3.0.4':
1300
+ resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
1301
+
1302
  '@types/http-cache-semantics@4.0.4':
1303
  resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
1304
 
 
1314
  '@types/mdast@3.0.15':
1315
  resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==}
1316
 
1317
+ '@types/mdast@4.0.4':
1318
+ resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
1319
+
1320
  '@types/ms@0.7.34':
1321
  resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
1322
 
 
1350
  '@types/unist@2.0.10':
1351
  resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
1352
 
1353
+ '@types/unist@3.0.2':
1354
+ resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==}
1355
+
1356
  '@types/uuid@9.0.8':
1357
  resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
1358
 
 
1812
  detect-node-es@1.1.0:
1813
  resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
1814
 
1815
+ devlop@1.1.0:
1816
+ resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
1817
+
1818
  didyoumean@1.2.2:
1819
  resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
1820
 
 
2252
  resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
2253
  engines: {node: '>= 0.4'}
2254
 
2255
+ hast-util-from-parse5@8.0.1:
2256
+ resolution: {integrity: sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==}
2257
+
2258
  hast-util-parse-selector@2.2.5:
2259
  resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==}
2260
 
2261
+ hast-util-parse-selector@4.0.0:
2262
+ resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==}
2263
+
2264
+ hast-util-raw@9.0.3:
2265
+ resolution: {integrity: sha512-ICWvVOF2fq4+7CMmtCPD5CM4QKjPbHpPotE6+8tDooV0ZuyJVUzHsrNX+O5NaRbieTf0F7FfeBOMAwi6Td0+yQ==}
2266
+
2267
+ hast-util-to-parse5@8.0.0:
2268
+ resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==}
2269
+
2270
  hast-util-whitespace@2.0.1:
2271
  resolution: {integrity: sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==}
2272
 
2273
  hastscript@6.0.0:
2274
  resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==}
2275
 
2276
+ hastscript@8.0.0:
2277
+ resolution: {integrity: sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==}
2278
+
2279
  highlight.js@10.7.3:
2280
  resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
2281
 
2282
+ html-void-elements@3.0.0:
2283
+ resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
2284
+
2285
  http-cache-semantics@4.1.1:
2286
  resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
2287
 
 
2634
  mdast-util-to-hast@12.3.0:
2635
  resolution: {integrity: sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==}
2636
 
2637
+ mdast-util-to-hast@13.1.0:
2638
+ resolution: {integrity: sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==}
2639
+
2640
  mdast-util-to-markdown@1.5.0:
2641
  resolution: {integrity: sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==}
2642
 
 
2698
  micromark-util-character@1.2.0:
2699
  resolution: {integrity: sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==}
2700
 
2701
+ micromark-util-character@2.1.0:
2702
+ resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==}
2703
+
2704
  micromark-util-chunked@1.1.0:
2705
  resolution: {integrity: sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==}
2706
 
 
2719
  micromark-util-encode@1.1.0:
2720
  resolution: {integrity: sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==}
2721
 
2722
+ micromark-util-encode@2.0.0:
2723
+ resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==}
2724
+
2725
  micromark-util-html-tag-name@1.2.0:
2726
  resolution: {integrity: sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==}
2727
 
 
2734
  micromark-util-sanitize-uri@1.2.0:
2735
  resolution: {integrity: sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==}
2736
 
2737
+ micromark-util-sanitize-uri@2.0.0:
2738
+ resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==}
2739
+
2740
  micromark-util-subtokenize@1.1.0:
2741
  resolution: {integrity: sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==}
2742
 
2743
  micromark-util-symbol@1.1.0:
2744
  resolution: {integrity: sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==}
2745
 
2746
+ micromark-util-symbol@2.0.0:
2747
+ resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==}
2748
+
2749
  micromark-util-types@1.1.0:
2750
  resolution: {integrity: sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==}
2751
 
2752
+ micromark-util-types@2.0.0:
2753
+ resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==}
2754
+
2755
  micromark@3.2.0:
2756
  resolution: {integrity: sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==}
2757
 
 
2966
  parse-entities@2.0.0:
2967
  resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==}
2968
 
2969
+ parse5@7.1.2:
2970
+ resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
2971
+
2972
  path-exists@4.0.0:
2973
  resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
2974
  engines: {node: '>=8'}
 
3269
  resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
3270
  engines: {node: '>= 0.4'}
3271
 
3272
+ rehype-raw@7.0.0:
3273
+ resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==}
3274
+
3275
  remark-gfm@3.0.1:
3276
  resolution: {integrity: sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==}
3277
 
 
3635
  unist-util-is@5.2.1:
3636
  resolution: {integrity: sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==}
3637
 
3638
+ unist-util-is@6.0.0:
3639
+ resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
3640
+
3641
  unist-util-position@4.0.4:
3642
  resolution: {integrity: sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==}
3643
 
3644
+ unist-util-position@5.0.0:
3645
+ resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
3646
+
3647
  unist-util-stringify-position@3.0.3:
3648
  resolution: {integrity: sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==}
3649
 
3650
+ unist-util-stringify-position@4.0.0:
3651
+ resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
3652
+
3653
  unist-util-visit-parents@5.1.3:
3654
  resolution: {integrity: sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==}
3655
 
3656
+ unist-util-visit-parents@6.0.1:
3657
+ resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
3658
+
3659
  unist-util-visit@4.1.2:
3660
  resolution: {integrity: sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==}
3661
 
3662
+ unist-util-visit@5.0.0:
3663
+ resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
3664
+
3665
  update-browserslist-db@1.0.13:
3666
  resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
3667
  hasBin: true
 
3731
  engines: {node: '>=8'}
3732
  hasBin: true
3733
 
3734
+ vfile-location@5.0.2:
3735
+ resolution: {integrity: sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==}
3736
+
3737
  vfile-message@3.1.4:
3738
  resolution: {integrity: sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==}
3739
 
3740
+ vfile-message@4.0.2:
3741
+ resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
3742
+
3743
  vfile@5.3.7:
3744
  resolution: {integrity: sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==}
3745
 
3746
+ vfile@6.0.1:
3747
+ resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==}
3748
+
3749
  vue@3.4.23:
3750
  resolution: {integrity: sha512-X1y6yyGJ28LMUBJ0k/qIeKHstGd+BlWQEOT40x3auJFTmpIhpbKLgN7EFsqalnJXq1Km5ybDEsp6BhuWKciUDg==}
3751
  peerDependencies:
 
3754
  typescript:
3755
  optional: true
3756
 
3757
+ web-namespaces@2.0.1:
3758
+ resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
3759
+
3760
  web-streams-polyfill@3.3.3:
3761
  resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
3762
  engines: {node: '>= 8'}
 
4744
  optionalDependencies:
4745
  '@types/react': 18.2.79
4746
 
4747
+ '@radix-ui/react-dialog@1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
4748
+ dependencies:
4749
+ '@babel/runtime': 7.24.4
4750
+ '@radix-ui/primitive': 1.0.1
4751
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.2.0)
4752
+ '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.2.0)
4753
+ '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
4754
+ '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.79)(react@18.2.0)
4755
+ '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
4756
+ '@radix-ui/react-id': 1.0.1(@types/react@18.2.79)(react@18.2.0)
4757
+ '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
4758
+ '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
4759
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
4760
+ '@radix-ui/react-slot': 1.0.2(@types/react@18.2.79)(react@18.2.0)
4761
+ '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.79)(react@18.2.0)
4762
+ aria-hidden: 1.2.4
4763
+ react: 18.2.0
4764
+ react-dom: 18.2.0(react@18.2.0)
4765
+ react-remove-scroll: 2.5.5(@types/react@18.2.79)(react@18.2.0)
4766
+ optionalDependencies:
4767
+ '@types/react': 18.2.79
4768
+ '@types/react-dom': 18.2.25
4769
+
4770
  '@radix-ui/react-direction@1.0.1(@types/react@18.2.79)(react@18.2.0)':
4771
  dependencies:
4772
  '@babel/runtime': 7.24.4
 
5407
  dependencies:
5408
  '@types/unist': 2.0.10
5409
 
5410
+ '@types/hast@3.0.4':
5411
+ dependencies:
5412
+ '@types/unist': 2.0.10
5413
+
5414
  '@types/http-cache-semantics@4.0.4': {}
5415
 
5416
  '@types/json5@0.0.29': {}
 
5425
  dependencies:
5426
  '@types/unist': 2.0.10
5427
 
5428
+ '@types/mdast@4.0.4':
5429
+ dependencies:
5430
+ '@types/unist': 3.0.2
5431
+
5432
  '@types/ms@0.7.34': {}
5433
 
5434
  '@types/node-fetch@2.6.11':
 
5469
 
5470
  '@types/unist@2.0.10': {}
5471
 
5472
+ '@types/unist@3.0.2': {}
5473
+
5474
  '@types/uuid@9.0.8': {}
5475
 
5476
  '@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5)':
 
5974
 
5975
  detect-node-es@1.1.0: {}
5976
 
5977
+ devlop@1.1.0:
5978
+ dependencies:
5979
+ dequal: 2.0.3
5980
+
5981
  didyoumean@1.2.2: {}
5982
 
5983
  diff@5.2.0: {}
 
6571
  dependencies:
6572
  function-bind: 1.1.2
6573
 
6574
+ hast-util-from-parse5@8.0.1:
6575
+ dependencies:
6576
+ '@types/hast': 3.0.4
6577
+ '@types/unist': 3.0.2
6578
+ devlop: 1.1.0
6579
+ hastscript: 8.0.0
6580
+ property-information: 6.5.0
6581
+ vfile: 6.0.1
6582
+ vfile-location: 5.0.2
6583
+ web-namespaces: 2.0.1
6584
+
6585
  hast-util-parse-selector@2.2.5: {}
6586
 
6587
+ hast-util-parse-selector@4.0.0:
6588
+ dependencies:
6589
+ '@types/hast': 3.0.4
6590
+
6591
+ hast-util-raw@9.0.3:
6592
+ dependencies:
6593
+ '@types/hast': 3.0.4
6594
+ '@types/unist': 3.0.2
6595
+ '@ungap/structured-clone': 1.2.0
6596
+ hast-util-from-parse5: 8.0.1
6597
+ hast-util-to-parse5: 8.0.0
6598
+ html-void-elements: 3.0.0
6599
+ mdast-util-to-hast: 13.1.0
6600
+ parse5: 7.1.2
6601
+ unist-util-position: 5.0.0
6602
+ unist-util-visit: 5.0.0
6603
+ vfile: 6.0.1
6604
+ web-namespaces: 2.0.1
6605
+ zwitch: 2.0.4
6606
+
6607
+ hast-util-to-parse5@8.0.0:
6608
+ dependencies:
6609
+ '@types/hast': 3.0.4
6610
+ comma-separated-tokens: 2.0.3
6611
+ devlop: 1.1.0
6612
+ property-information: 6.5.0
6613
+ space-separated-tokens: 2.0.2
6614
+ web-namespaces: 2.0.1
6615
+ zwitch: 2.0.4
6616
+
6617
  hast-util-whitespace@2.0.1: {}
6618
 
6619
  hastscript@6.0.0:
 
6624
  property-information: 5.6.0
6625
  space-separated-tokens: 1.1.5
6626
 
6627
+ hastscript@8.0.0:
6628
+ dependencies:
6629
+ '@types/hast': 3.0.4
6630
+ comma-separated-tokens: 2.0.3
6631
+ hast-util-parse-selector: 4.0.0
6632
+ property-information: 6.5.0
6633
+ space-separated-tokens: 2.0.2
6634
+
6635
  highlight.js@10.7.3: {}
6636
 
6637
+ html-void-elements@3.0.0: {}
6638
+
6639
  http-cache-semantics@4.1.1: {}
6640
 
6641
  http2-wrapper@1.0.3:
 
7012
  unist-util-position: 4.0.4
7013
  unist-util-visit: 4.1.2
7014
 
7015
+ mdast-util-to-hast@13.1.0:
7016
+ dependencies:
7017
+ '@types/hast': 3.0.4
7018
+ '@types/mdast': 4.0.4
7019
+ '@ungap/structured-clone': 1.2.0
7020
+ devlop: 1.1.0
7021
+ micromark-util-sanitize-uri: 2.0.0
7022
+ trim-lines: 3.0.1
7023
+ unist-util-position: 5.0.0
7024
+ unist-util-visit: 5.0.0
7025
+ vfile: 6.0.1
7026
+
7027
  mdast-util-to-markdown@1.5.0:
7028
  dependencies:
7029
  '@types/mdast': 3.0.15
 
7169
  micromark-util-symbol: 1.1.0
7170
  micromark-util-types: 1.1.0
7171
 
7172
+ micromark-util-character@2.1.0:
7173
+ dependencies:
7174
+ micromark-util-symbol: 2.0.0
7175
+ micromark-util-types: 2.0.0
7176
+
7177
  micromark-util-chunked@1.1.0:
7178
  dependencies:
7179
  micromark-util-symbol: 1.1.0
 
7202
 
7203
  micromark-util-encode@1.1.0: {}
7204
 
7205
+ micromark-util-encode@2.0.0: {}
7206
+
7207
  micromark-util-html-tag-name@1.2.0: {}
7208
 
7209
  micromark-util-normalize-identifier@1.1.0:
 
7220
  micromark-util-encode: 1.1.0
7221
  micromark-util-symbol: 1.1.0
7222
 
7223
+ micromark-util-sanitize-uri@2.0.0:
7224
+ dependencies:
7225
+ micromark-util-character: 2.1.0
7226
+ micromark-util-encode: 2.0.0
7227
+ micromark-util-symbol: 2.0.0
7228
+
7229
  micromark-util-subtokenize@1.1.0:
7230
  dependencies:
7231
  micromark-util-chunked: 1.1.0
 
7235
 
7236
  micromark-util-symbol@1.1.0: {}
7237
 
7238
+ micromark-util-symbol@2.0.0: {}
7239
+
7240
  micromark-util-types@1.1.0: {}
7241
 
7242
+ micromark-util-types@2.0.0: {}
7243
+
7244
  micromark@3.2.0:
7245
  dependencies:
7246
  '@types/debug': 4.1.12
 
7464
  is-decimal: 1.0.4
7465
  is-hexadecimal: 1.0.4
7466
 
7467
+ parse5@7.1.2:
7468
+ dependencies:
7469
+ entities: 4.5.0
7470
+
7471
  path-exists@4.0.0: {}
7472
 
7473
  path-is-absolute@1.0.1: {}
 
7783
  es-errors: 1.3.0
7784
  set-function-name: 2.0.2
7785
 
7786
+ rehype-raw@7.0.0:
7787
+ dependencies:
7788
+ '@types/hast': 3.0.4
7789
+ hast-util-raw: 9.0.3
7790
+ vfile: 6.0.1
7791
+
7792
  remark-gfm@3.0.1:
7793
  dependencies:
7794
  '@types/mdast': 3.0.15
 
8250
  dependencies:
8251
  '@types/unist': 2.0.10
8252
 
8253
+ unist-util-is@6.0.0:
8254
+ dependencies:
8255
+ '@types/unist': 3.0.2
8256
+
8257
  unist-util-position@4.0.4:
8258
  dependencies:
8259
  '@types/unist': 2.0.10
8260
 
8261
+ unist-util-position@5.0.0:
8262
+ dependencies:
8263
+ '@types/unist': 3.0.2
8264
+
8265
  unist-util-stringify-position@3.0.3:
8266
  dependencies:
8267
  '@types/unist': 2.0.10
8268
 
8269
+ unist-util-stringify-position@4.0.0:
8270
+ dependencies:
8271
+ '@types/unist': 3.0.2
8272
+
8273
  unist-util-visit-parents@5.1.3:
8274
  dependencies:
8275
  '@types/unist': 2.0.10
8276
  unist-util-is: 5.2.1
8277
 
8278
+ unist-util-visit-parents@6.0.1:
8279
+ dependencies:
8280
+ '@types/unist': 3.0.2
8281
+ unist-util-is: 6.0.0
8282
+
8283
  unist-util-visit@4.1.2:
8284
  dependencies:
8285
  '@types/unist': 2.0.10
8286
  unist-util-is: 5.2.1
8287
  unist-util-visit-parents: 5.1.3
8288
 
8289
+ unist-util-visit@5.0.0:
8290
+ dependencies:
8291
+ '@types/unist': 3.0.2
8292
+ unist-util-is: 6.0.0
8293
+ unist-util-visit-parents: 6.0.1
8294
+
8295
  update-browserslist-db@1.0.13(browserslist@4.23.0):
8296
  dependencies:
8297
  browserslist: 4.23.0
 
8349
  kleur: 4.1.5
8350
  sade: 1.8.1
8351
 
8352
+ vfile-location@5.0.2:
8353
+ dependencies:
8354
+ '@types/unist': 3.0.2
8355
+ vfile: 6.0.1
8356
+
8357
  vfile-message@3.1.4:
8358
  dependencies:
8359
  '@types/unist': 2.0.10
8360
  unist-util-stringify-position: 3.0.3
8361
 
8362
+ vfile-message@4.0.2:
8363
+ dependencies:
8364
+ '@types/unist': 3.0.2
8365
+ unist-util-stringify-position: 4.0.0
8366
+
8367
  vfile@5.3.7:
8368
  dependencies:
8369
  '@types/unist': 2.0.10
 
8371
  unist-util-stringify-position: 3.0.3
8372
  vfile-message: 3.1.4
8373
 
8374
+ vfile@6.0.1:
8375
+ dependencies:
8376
+ '@types/unist': 3.0.2
8377
+ unist-util-stringify-position: 4.0.0
8378
+ vfile-message: 4.0.2
8379
+
8380
  vue@3.4.23(typescript@5.4.5):
8381
  dependencies:
8382
  '@vue/compiler-dom': 3.4.23
 
8387
  optionalDependencies:
8388
  typescript: 5.4.5
8389
 
8390
+ web-namespaces@2.0.1: {}
8391
+
8392
  web-streams-polyfill@3.3.3: {}
8393
 
8394
  web-streams-polyfill@4.0.0-beta.3: {}