@surph_ai/sdk 0.0.1
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/auth/index.js +147 -0
- package/base/vinely-base/.nvmrc +1 -0
- package/base/vinely-base/README.md +30 -0
- package/base/vinely-base/app.js +5 -0
- package/base/vinely-base/declarations.d.ts +1 -0
- package/base/vinely-base/package.json +103 -0
- package/base/vinely-base/public/css/globals-2.css +3699 -0
- package/base/vinely-base/public/css/globals.css +3695 -0
- package/base/vinely-base/public/js/app.js +1 -0
- package/base/vinely-base/public/js/jquery.js +2 -0
- package/base/vinely-base/scratch.js +21 -0
- package/base/vinely-base/src/client/components/app-sidebar.tsx +59 -0
- package/base/vinely-base/src/client/components/assistant-ui/markdown-text.tsx +153 -0
- package/base/vinely-base/src/client/components/assistant-ui/thread-list.tsx +67 -0
- package/base/vinely-base/src/client/components/assistant-ui/thread.tsx +666 -0
- package/base/vinely-base/src/client/components/assistant-ui/tool-fallback.tsx +44 -0
- package/base/vinely-base/src/client/components/assistant-ui/tooltip-icon-button.tsx +44 -0
- package/base/vinely-base/src/client/components/ui/breadcrumb.tsx +109 -0
- package/base/vinely-base/src/client/components/ui/button.tsx +59 -0
- package/base/vinely-base/src/client/components/ui/input.tsx +21 -0
- package/base/vinely-base/src/client/components/ui/separator.tsx +28 -0
- package/base/vinely-base/src/client/components/ui/sheet.tsx +139 -0
- package/base/vinely-base/src/client/components/ui/sidebar.tsx +726 -0
- package/base/vinely-base/src/client/components/ui/skeleton.tsx +14 -0
- package/base/vinely-base/src/client/components/ui/tooltip.tsx +61 -0
- package/base/vinely-base/src/client/components/vines-sidebar.tsx +182 -0
- package/base/vinely-base/src/client/contexts/SessionContext.tsx +28 -0
- package/base/vinely-base/src/client/contexts/SessionReducer.tsx +32 -0
- package/base/vinely-base/src/client/hooks/use-mobile.ts +19 -0
- package/base/vinely-base/src/client/index.tsx +154 -0
- package/base/vinely-base/src/client/lib/API.ts +155 -0
- package/base/vinely-base/src/client/lib/RPC.ts +49 -0
- package/base/vinely-base/src/client/lib/utils.ts +96 -0
- package/base/vinely-base/src/server/index.ts +63 -0
- package/base/vinely-base/src/server/routes/api.ts +38 -0
- package/base/vinely-base/src/server/routes/chat.ts +133 -0
- package/base/vinely-base/src/server/routes/main.ts +36 -0
- package/base/vinely-base/src/server/routes/mcp.ts +52 -0
- package/base/vinely-base/src/server/routes/rpc.ts +64 -0
- package/base/vinely-base/src/server/routes/thread.ts +44 -0
- package/base/vinely-base/src/server/utils/APIMgr.ts +156 -0
- package/base/vinely-base/src/server/utils/Auth.ts +235 -0
- package/base/vinely-base/src/server/utils/fetchManifest.ts +15 -0
- package/base/vinely-base/src/server/utils/mcp-auth.ts +251 -0
- package/base/vinely-base/tsconfig.json +16 -0
- package/base/vinely-base/views/landing.html +187 -0
- package/base/vinely-base/views/partials/imports.dev.html +3 -0
- package/base/vinely-base/webpack.config.js +112 -0
- package/deploy/Dockerfile +9 -0
- package/deploy/index.js +244 -0
- package/index.js +266 -0
- package/package.json +28 -0
- package/scaffold/app/gulpfile.js +12 -0
- package/scaffold/app/package.json +24 -0
- package/scaffold/app/src/index.js +14 -0
- package/scaffold/index.js +171 -0
- package/scaffold/project/README.md +28 -0
- package/scaffold/project/app.js +20 -0
- package/scaffold/project/apps/README.md +1 -0
- package/scaffold/project/env.txt +4 -0
- package/scaffold/project/package-lock.json +2459 -0
- package/scaffold/project/package.json +21 -0
- package/scaffold/project/public/css/bootstrap.css +5926 -0
- package/scaffold/project/public/js/app.js +1 -0
- package/scaffold/project/public/js/jquery.js +2 -0
- package/scaffold/project/routes/index.js +8 -0
- package/scaffold/project/templates/index.mustache +20 -0
- package/utils/Realm.js +60 -0
- package/utils/http.js +22 -0
- package/utils/index.js +276 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { cn } from "../../lib/utils"
|
|
3
|
+
|
|
4
|
+
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
|
|
5
|
+
return (
|
|
6
|
+
<div
|
|
7
|
+
data-slot="skeleton"
|
|
8
|
+
className={cn("bg-accent animate-pulse rounded-md", className)}
|
|
9
|
+
{...props}
|
|
10
|
+
/>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { Skeleton }
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
5
|
+
|
|
6
|
+
import { cn } from "../../lib/utils";
|
|
7
|
+
|
|
8
|
+
function TooltipProvider({
|
|
9
|
+
delayDuration = 0,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
|
12
|
+
return (
|
|
13
|
+
<TooltipPrimitive.Provider
|
|
14
|
+
data-slot="tooltip-provider"
|
|
15
|
+
delayDuration={delayDuration}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function Tooltip({
|
|
22
|
+
...props
|
|
23
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
|
24
|
+
return (
|
|
25
|
+
<TooltipProvider>
|
|
26
|
+
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
27
|
+
</TooltipProvider>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function TooltipTrigger({
|
|
32
|
+
...props
|
|
33
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
|
34
|
+
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function TooltipContent({
|
|
38
|
+
className,
|
|
39
|
+
sideOffset = 0,
|
|
40
|
+
children,
|
|
41
|
+
...props
|
|
42
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
|
43
|
+
return (
|
|
44
|
+
<TooltipPrimitive.Portal>
|
|
45
|
+
<TooltipPrimitive.Content
|
|
46
|
+
data-slot="tooltip-content"
|
|
47
|
+
sideOffset={sideOffset}
|
|
48
|
+
className={cn(
|
|
49
|
+
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
|
50
|
+
className
|
|
51
|
+
)}
|
|
52
|
+
{...props}
|
|
53
|
+
>
|
|
54
|
+
{children}
|
|
55
|
+
<TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
|
|
56
|
+
</TooltipPrimitive.Content>
|
|
57
|
+
</TooltipPrimitive.Portal>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
import React, { useContext, useState, useEffect } from "react"
|
|
3
|
+
import { MessagesSquare } from "lucide-react"
|
|
4
|
+
import {
|
|
5
|
+
Sidebar,
|
|
6
|
+
SidebarContent,
|
|
7
|
+
SidebarFooter,
|
|
8
|
+
SidebarHeader,
|
|
9
|
+
SidebarMenu,
|
|
10
|
+
SidebarMenuButton,
|
|
11
|
+
SidebarMenuItem,
|
|
12
|
+
SidebarRail,
|
|
13
|
+
} from "./ui/sidebar"
|
|
14
|
+
import { SessionContext } from '../contexts/SessionContext'
|
|
15
|
+
import { useAssistantRuntime } from '@assistant-ui/react'
|
|
16
|
+
|
|
17
|
+
const convertToArray = (data: Record<string, any> | undefined): any[] => {
|
|
18
|
+
if (!data) {
|
|
19
|
+
return []
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const _array: any[] = []
|
|
23
|
+
for (const key of Object.keys(data)) {
|
|
24
|
+
const datasource = data[key]
|
|
25
|
+
if (datasource.index === '') {
|
|
26
|
+
continue
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_array.push(datasource)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return _array
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const contextRequest = async (datasource: Record<string, any>): Promise<void> => {
|
|
36
|
+
try {
|
|
37
|
+
await axios({
|
|
38
|
+
url: '/context',
|
|
39
|
+
method: 'post',
|
|
40
|
+
// data: { context: datasource },
|
|
41
|
+
headers: { Accept: 'application/json' },
|
|
42
|
+
data: {
|
|
43
|
+
context: {
|
|
44
|
+
vine: datasource.slug
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
})
|
|
48
|
+
} catch (error) {
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const VinesSidebar = ({ items }: any) => {
|
|
54
|
+
const { context, dispatch } = useContext(SessionContext)
|
|
55
|
+
const { currentSpace, currentDatasource } = context
|
|
56
|
+
const [ indexed, setIndexed ] = useState<Record<string, any>[] | null>(null)
|
|
57
|
+
|
|
58
|
+
const assistantRuntime = useAssistantRuntime() as any
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (indexed) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!items) {
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const _indexed = convertToArray(items).filter(datasource => datasource.index !== '')
|
|
70
|
+
setIndexed(_indexed)
|
|
71
|
+
|
|
72
|
+
if (currentDatasource) {
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const datasource = _indexed[0]
|
|
77
|
+
dispatch({ type: 'SET_CURRENT_DATASOURCE', data: datasource })
|
|
78
|
+
}, [])
|
|
79
|
+
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (!currentDatasource) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
contextRequest(currentDatasource)
|
|
86
|
+
}, [currentDatasource])
|
|
87
|
+
|
|
88
|
+
const selectItem = async (e: any): Promise<void> => {
|
|
89
|
+
if (e) {
|
|
90
|
+
e.preventDefault()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const threadId = e.target.getAttribute('data-thread')
|
|
94
|
+
const datasourceSlug = e.target.getAttribute('data-source')
|
|
95
|
+
const datasource = items[datasourceSlug]
|
|
96
|
+
|
|
97
|
+
if (currentDatasource.slug === datasource.slug) { // ignore
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const { threadIds } = assistantRuntime.threads._core._state._baseValue
|
|
102
|
+
if (threadIds.length === 0) { // no conversation started, user toggling between options.
|
|
103
|
+
dispatch({ type: 'SET_CURRENT_DATASOURCE', data: datasource })
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const previous = document.getElementById(`menu-${currentDatasource.slug}`)
|
|
108
|
+
if (previous?.getAttribute('data-thread') === '-1') {
|
|
109
|
+
const _threadId = threadIds[0]
|
|
110
|
+
const items = Array.from(document.getElementsByClassName('datasource-menu-item'))
|
|
111
|
+
let found = false
|
|
112
|
+
for (const item of items) {
|
|
113
|
+
const dataThread = item.getAttribute('data-thread')
|
|
114
|
+
if (dataThread === _threadId) {
|
|
115
|
+
found = true
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (found === false)
|
|
121
|
+
previous?.setAttribute('data-thread', _threadId)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (threadId === '-1') {
|
|
125
|
+
// console.log('Assign thread id: ' + JSON.stringify(threadIds))
|
|
126
|
+
await assistantRuntime.threads.switchToNewThread()
|
|
127
|
+
dispatch({ type: 'SET_CURRENT_DATASOURCE', data: datasource })
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
await assistantRuntime.threads.switchToThread(threadId)
|
|
132
|
+
dispatch({ type: 'SET_CURRENT_DATASOURCE', data: datasource })
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<Sidebar>
|
|
137
|
+
<SidebarContent>
|
|
138
|
+
{/* <ThreadList /> */}
|
|
139
|
+
<div className="p-4">
|
|
140
|
+
<ul className="sidebar-list">
|
|
141
|
+
{indexed ? indexed.map((ds: any) => (
|
|
142
|
+
<li key={ds.slug}>
|
|
143
|
+
<a
|
|
144
|
+
href="#"
|
|
145
|
+
className="datasource-menu-item"
|
|
146
|
+
onClick={selectItem}
|
|
147
|
+
id={`menu-${ds.slug}`}
|
|
148
|
+
data-source={ds.slug}
|
|
149
|
+
data-thread="-1"
|
|
150
|
+
style={{
|
|
151
|
+
color: currentDatasource
|
|
152
|
+
? (ds.slug === currentDatasource.slug) ? '#fff' : '#555'
|
|
153
|
+
: '#333'
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
{ds.name}
|
|
157
|
+
</a>
|
|
158
|
+
</li>
|
|
159
|
+
)): null}
|
|
160
|
+
</ul>
|
|
161
|
+
</div>
|
|
162
|
+
</SidebarContent>
|
|
163
|
+
|
|
164
|
+
<SidebarRail />
|
|
165
|
+
<SidebarFooter>
|
|
166
|
+
<SidebarMenu>
|
|
167
|
+
<SidebarMenuItem style={{ paddingLeft: 10, paddingBottom: 6 }}>
|
|
168
|
+
<a
|
|
169
|
+
href="https://vinely.ai"
|
|
170
|
+
style={{ fontSize: 12, color: '#fff' }}
|
|
171
|
+
target="_blank"
|
|
172
|
+
>
|
|
173
|
+
Powered by <span className="color-accent">Vinely</span>
|
|
174
|
+
</a>
|
|
175
|
+
</SidebarMenuItem>
|
|
176
|
+
</SidebarMenu>
|
|
177
|
+
</SidebarFooter>
|
|
178
|
+
</Sidebar>
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export { VinesSidebar }
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React, { createContext, useReducer } from 'react'
|
|
2
|
+
import sessionReducer from './SessionReducer'
|
|
3
|
+
|
|
4
|
+
interface ContextProps {
|
|
5
|
+
children: any,
|
|
6
|
+
initial: any
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const SessionContext: React.Context<any> = createContext({})
|
|
10
|
+
|
|
11
|
+
const SessionContextProvider = ({ children, initial }: ContextProps) => {
|
|
12
|
+
const initialContext = {
|
|
13
|
+
...initial,
|
|
14
|
+
settings: initial.config
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const [context, dispatch] = useReducer(sessionReducer, {
|
|
18
|
+
...initialContext
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<SessionContext.Provider value={{context, dispatch}}>
|
|
23
|
+
{children}
|
|
24
|
+
</SessionContext.Provider>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default SessionContextProvider
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export default (context: any, action: any) => {
|
|
2
|
+
const { data, type } = action;
|
|
3
|
+
switch (type) {
|
|
4
|
+
// case 'SET_CURRENT_USER': {
|
|
5
|
+
// console.log('SET_CURRENT_USER: ' + JSON.stringify(data))
|
|
6
|
+
// return {
|
|
7
|
+
// ...context,
|
|
8
|
+
// user: data
|
|
9
|
+
// }
|
|
10
|
+
// }
|
|
11
|
+
|
|
12
|
+
case 'SET_CURRENT_SPACE': {
|
|
13
|
+
console.log('SET_CURRENT_SPACE: ' + JSON.stringify(data))
|
|
14
|
+
return {
|
|
15
|
+
...context,
|
|
16
|
+
currentSpace: data,
|
|
17
|
+
currentDatasource: null
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
case 'SET_CURRENT_DATASOURCE': {
|
|
22
|
+
console.log('SET_CURRENT_DATASOURCE: ' + JSON.stringify(data))
|
|
23
|
+
return {
|
|
24
|
+
...context,
|
|
25
|
+
currentDatasource: data
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
default:
|
|
30
|
+
return context;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
const MOBILE_BREAKPOINT = 768
|
|
4
|
+
|
|
5
|
+
export function useIsMobile() {
|
|
6
|
+
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
|
|
7
|
+
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
|
|
10
|
+
const onChange = () => {
|
|
11
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
|
12
|
+
}
|
|
13
|
+
mql.addEventListener("change", onChange)
|
|
14
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
|
15
|
+
return () => mql.removeEventListener("change", onChange)
|
|
16
|
+
}, [])
|
|
17
|
+
|
|
18
|
+
return !!isMobile
|
|
19
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import React, { useMemo, useEffect, useState } from 'react'
|
|
2
|
+
import ReactDOM from 'react-dom/client'
|
|
3
|
+
import Markdown from 'react-markdown'
|
|
4
|
+
import { BrowserRouter as Router, Route, Switch, useParams } from 'react-router-dom'
|
|
5
|
+
import { AssistantRuntimeProvider } from "@assistant-ui/react"
|
|
6
|
+
import { useChatRuntime } from "@assistant-ui/react-ai-sdk"
|
|
7
|
+
import { Thread } from "./components/assistant-ui/thread"
|
|
8
|
+
import {
|
|
9
|
+
SidebarInset,
|
|
10
|
+
SidebarProvider,
|
|
11
|
+
// SidebarTrigger,
|
|
12
|
+
} from "./components/ui/sidebar"
|
|
13
|
+
import { VinesSidebar } from "./components/vines-sidebar"
|
|
14
|
+
import SessionContextProvider from './contexts/SessionContext'
|
|
15
|
+
import { fetchMessages } from './lib/utils'
|
|
16
|
+
import "katex/dist/katex.min.css";
|
|
17
|
+
|
|
18
|
+
declare global {
|
|
19
|
+
interface Window {
|
|
20
|
+
__CONTEXT__: Record<string, any>
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { vineyard } = window.__CONTEXT__
|
|
25
|
+
|
|
26
|
+
const PlainText = () => {
|
|
27
|
+
const [ messages, setMessages ] = useState<Record<string, string>[] | null>(null)
|
|
28
|
+
const { thread_id } = useParams() as any
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const _fetchMessages = async () => {
|
|
32
|
+
try {
|
|
33
|
+
const payload = await fetchMessages(vineyard.slug, thread_id)
|
|
34
|
+
setMessages(payload.messages)
|
|
35
|
+
} catch (error: any) {
|
|
36
|
+
console.log('FETCH MESSAGES ERR: ' + error.message)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
_fetchMessages()
|
|
41
|
+
}, [])
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div className="markdown" style={{ overflow: 'scroll' }}>
|
|
45
|
+
{messages?.map(msg => {
|
|
46
|
+
if (msg.role === 'user') {
|
|
47
|
+
return (
|
|
48
|
+
<div key={msg.id} className="message-user">
|
|
49
|
+
<div style={{ textAlign: 'right'}}>
|
|
50
|
+
<small>{msg.createdAt}</small>
|
|
51
|
+
<p>{msg.text}</p>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<Markdown key={msg.id}>
|
|
59
|
+
{msg.text}
|
|
60
|
+
</Markdown>
|
|
61
|
+
)
|
|
62
|
+
})}
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const Entry = () => {
|
|
68
|
+
const runtime = useChatRuntime()
|
|
69
|
+
|
|
70
|
+
const metadata = useMemo(() => (vineyard.metadata || {}), [])
|
|
71
|
+
|
|
72
|
+
// useEffect(() => {
|
|
73
|
+
// console.log('THREAD: ' + JSON.stringify(thread))
|
|
74
|
+
// }, [thread])
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<Router>
|
|
78
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
79
|
+
<SidebarProvider>
|
|
80
|
+
<div className="flex h-dvh w-full pr-0.5">
|
|
81
|
+
<VinesSidebar items={vineyard.datasources} />
|
|
82
|
+
<SidebarInset>
|
|
83
|
+
<header id="nav-header" className="flex h-16 shrink-0 items-center px-4 header">
|
|
84
|
+
<div style={{ flex: 1 }}></div>
|
|
85
|
+
<div style={{ flex: 1, textAlign: 'center', color: '#e8e8e3', paddingTop: 12 }}>
|
|
86
|
+
{metadata.logo
|
|
87
|
+
? <img
|
|
88
|
+
src={metadata.logo}
|
|
89
|
+
style={{ maxWidth: 220, margin: 'auto', transition: 'all 0.25s linear' }}
|
|
90
|
+
onMouseEnter={(e: any) => {
|
|
91
|
+
e.target.style.opacity = '0.6'
|
|
92
|
+
if (e.target.classList.contains('effect-shine')) {
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
e.target.style.transition = 'none'
|
|
98
|
+
e.target.style.opacity = '1'
|
|
99
|
+
e.target.classList.add('effect-shine')
|
|
100
|
+
}, 750)
|
|
101
|
+
}}
|
|
102
|
+
onMouseLeave={(e: any) => {
|
|
103
|
+
e.target.style.transition = 'all 0.25s linear'
|
|
104
|
+
e.target.style.opacity = '0.6'
|
|
105
|
+
|
|
106
|
+
if (!e.target.classList.contains('effect-shine')) {
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
setTimeout(() => {
|
|
111
|
+
e.target.style.opacity = '1'
|
|
112
|
+
e.target.classList.remove('effect-shine')
|
|
113
|
+
}, (350))
|
|
114
|
+
}}
|
|
115
|
+
/>
|
|
116
|
+
: vineyard.name
|
|
117
|
+
}
|
|
118
|
+
</div>
|
|
119
|
+
<div style={{ flex: 1 }}></div>
|
|
120
|
+
</header>
|
|
121
|
+
{/* <div className="flex-1 overflow-hidden"> */}
|
|
122
|
+
<Switch>
|
|
123
|
+
<Route exact path="/">
|
|
124
|
+
<Thread />
|
|
125
|
+
</Route>
|
|
126
|
+
|
|
127
|
+
<Route exact path="/thread/:thread_id">
|
|
128
|
+
<PlainText />
|
|
129
|
+
</Route>
|
|
130
|
+
</Switch>
|
|
131
|
+
{/* </div> */}
|
|
132
|
+
</SidebarInset>
|
|
133
|
+
</div>
|
|
134
|
+
</SidebarProvider>
|
|
135
|
+
</AssistantRuntimeProvider>
|
|
136
|
+
</Router>
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const RootLayout = ({ children }: any) => {
|
|
141
|
+
return (
|
|
142
|
+
<SessionContextProvider
|
|
143
|
+
initial={{
|
|
144
|
+
currentSpace: vineyard,
|
|
145
|
+
currentDatasource: null
|
|
146
|
+
}}
|
|
147
|
+
>
|
|
148
|
+
<Entry />
|
|
149
|
+
</SessionContextProvider>
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
|
|
154
|
+
root.render(<RootLayout children={null} />)
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
|
|
3
|
+
type ReqHeaders = Record<string, string>
|
|
4
|
+
type ReqBody = Record<string, any>
|
|
5
|
+
|
|
6
|
+
const queryParamsToString = (query: any) => {
|
|
7
|
+
const keys = Object.keys(query)
|
|
8
|
+
const lastIndex = keys.length - 1
|
|
9
|
+
let queryString = ''
|
|
10
|
+
keys.forEach((key, i) => {
|
|
11
|
+
queryString += `${key}=${query[key]}`
|
|
12
|
+
if (i !== lastIndex)
|
|
13
|
+
queryString += '&'
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
return queryString
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const parseError = (err: any) => {
|
|
20
|
+
if (!err.response) {
|
|
21
|
+
return err
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!err.response.data) {
|
|
25
|
+
return err
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { status, data } = err.response
|
|
29
|
+
const error = new Error(JSON.stringify({
|
|
30
|
+
...data,
|
|
31
|
+
status,
|
|
32
|
+
}))
|
|
33
|
+
|
|
34
|
+
error.name = data.type
|
|
35
|
+
return error
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const API_VERSION = '/api'
|
|
39
|
+
// const API_VERSION = `http://localhost:3000/rest`
|
|
40
|
+
|
|
41
|
+
const DEFAULT_HEADERS = {
|
|
42
|
+
'Accept': 'application/json',
|
|
43
|
+
'Content-Type': 'application/json',
|
|
44
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
45
|
+
// 'Cache-Control': 'no-cache',
|
|
46
|
+
// 'Pragma': 'no-cache',
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class API {
|
|
50
|
+
constructor() {
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
defaultHeaders(reqHeaders: any) {
|
|
55
|
+
const headers: any = {
|
|
56
|
+
...DEFAULT_HEADERS,
|
|
57
|
+
// 'Client-TzOffset': tzOffsetHeader(),
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!reqHeaders)
|
|
61
|
+
return headers
|
|
62
|
+
|
|
63
|
+
Object.keys(reqHeaders).forEach((headerName: string) => {
|
|
64
|
+
headers[headerName] = reqHeaders[headerName]
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
return headers
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async get(endpoint: string, query?: ReqBody, reqHeaders?: ReqHeaders) {
|
|
71
|
+
const headers = this.defaultHeaders(reqHeaders)
|
|
72
|
+
|
|
73
|
+
const url = query === null
|
|
74
|
+
? `${API_VERSION}${endpoint}`
|
|
75
|
+
: `${API_VERSION}${endpoint}?${queryParamsToString(query)}`
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const { data } = await axios({
|
|
79
|
+
url,
|
|
80
|
+
method: 'get',
|
|
81
|
+
headers,
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
return data
|
|
85
|
+
} catch (error) {
|
|
86
|
+
throw parseError(error)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async post(endpoint: string, body: ReqBody, reqHeaders?: ReqHeaders) {
|
|
91
|
+
const headers = this.defaultHeaders(reqHeaders)
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const { data } = await axios({
|
|
95
|
+
url: `${API_VERSION}${endpoint}`,
|
|
96
|
+
method: 'post',
|
|
97
|
+
data: body,
|
|
98
|
+
headers,
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
return data
|
|
102
|
+
} catch (error) {
|
|
103
|
+
throw parseError(error)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async put(endpoint: string, body: ReqBody, reqHeaders: ReqHeaders | null, isFormData?: boolean) {
|
|
108
|
+
try {
|
|
109
|
+
const headers = this.defaultHeaders(reqHeaders)
|
|
110
|
+
|
|
111
|
+
if (isFormData === true) {
|
|
112
|
+
const resp = await axios.put(`${API_VERSION}${endpoint}`, body, {
|
|
113
|
+
responseType: 'blob',
|
|
114
|
+
headers: {
|
|
115
|
+
...headers,
|
|
116
|
+
'content-type': 'multipart/form-data',
|
|
117
|
+
},
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
return resp.data
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const { data } = await axios({
|
|
124
|
+
url: `${API_VERSION}${endpoint}`,
|
|
125
|
+
method: 'put',
|
|
126
|
+
data: body,
|
|
127
|
+
headers,
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
return data
|
|
131
|
+
} catch (error) {
|
|
132
|
+
throw parseError(error)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/*
|
|
137
|
+
async delete(endpoint, body, reqHeaders) {
|
|
138
|
+
const headers = this.defaultHeaders(reqHeaders)
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const { data } = await axios({
|
|
142
|
+
url: `${API_VERSION}${endpoint}`,
|
|
143
|
+
method: 'delete',
|
|
144
|
+
headers,
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
return data
|
|
148
|
+
} catch (error) {
|
|
149
|
+
throw parseError(error)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
*/
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export default new API()
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
|
|
3
|
+
class RPC {
|
|
4
|
+
constructor() {
|
|
5
|
+
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
defaultHeaders(reqHeaders: any) {
|
|
10
|
+
const headers: any = {
|
|
11
|
+
...DEFAULT_HEADERS,
|
|
12
|
+
// 'Client-TzOffset': tzOffsetHeader(),
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!reqHeaders)
|
|
16
|
+
return headers
|
|
17
|
+
|
|
18
|
+
Object.keys(reqHeaders).forEach((headerName: string) => {
|
|
19
|
+
headers[headerName] = reqHeaders[headerName]
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
return headers
|
|
23
|
+
}
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
async call(
|
|
27
|
+
service: string,
|
|
28
|
+
action: string | null,
|
|
29
|
+
args: Record<any, any>
|
|
30
|
+
): Promise<Record<any, any>> {
|
|
31
|
+
|
|
32
|
+
const url = action === null
|
|
33
|
+
? `/rpc/${service}`
|
|
34
|
+
: `/rpc/${service}/${action}`
|
|
35
|
+
|
|
36
|
+
const { data } = await axios({
|
|
37
|
+
url,
|
|
38
|
+
method: 'post',
|
|
39
|
+
data: args,
|
|
40
|
+
headers: {
|
|
41
|
+
Accept: 'application/json'
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
return data
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default new RPC()
|