From 509390569f8e0fa9941b94176300bb254ff2705a Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Tue, 3 Dec 2024 11:09:37 +0530 Subject: [PATCH] added context to history --- app/components/chat/BaseChat.tsx | 13 ++- app/components/chat/GitCloneButton.tsx | 94 ++++++++++++++++--- .../chatExportAndImport/ImportButtons.tsx | 2 +- app/lib/hooks/useGit.ts | 37 ++++++-- 4 files changed, 118 insertions(+), 28 deletions(-) diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index 8505c06..f1fd75e 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -22,7 +22,6 @@ import { ExportChatButton } from '~/components/chat/chatExportAndImport/ExportCh import { ImportButtons } from '~/components/chat/chatExportAndImport/ImportButtons'; import { ExamplePrompts } from '~/components/chat/ExamplePrompts'; import GitCloneButton from './GitCloneButton'; -import * as Separator from '@radix-ui/react-separator'; // @ts-ignore TODO: Introduce proper types // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -256,11 +255,6 @@ export const BaseChat = React.forwardRef( Model Settings - - - -
-
(
- {!chatStarted && ImportButtons(importChat)} + {!chatStarted && ( +
+ {ImportButtons(importChat)} + +
+ )} {!chatStarted && ExamplePrompts(sendMessage)} {() => } diff --git a/app/components/chat/GitCloneButton.tsx b/app/components/chat/GitCloneButton.tsx index c280349..ed89912 100644 --- a/app/components/chat/GitCloneButton.tsx +++ b/app/components/chat/GitCloneButton.tsx @@ -1,7 +1,36 @@ -import { IconButton } from '~/components/ui/IconButton'; +import ignore from 'ignore'; import { useGit } from '~/lib/hooks/useGit'; +import type { Message } from 'ai'; +import WithTooltip from '~/components/ui/Tooltip'; -export default function GitCloneButton() { +const IGNORE_PATTERNS = [ + 'node_modules/**', + '.git/**', + '.github/**', + 'dist/**', + 'build/**', + '.next/**', + 'coverage/**', + '.cache/**', + '.vscode/**', + '.idea/**', + '**/*.log', + '**/.DS_Store', + '**/npm-debug.log*', + '**/yarn-debug.log*', + '**/yarn-error.log*', + '**/*lock.json', +]; + +const ig = ignore().add(IGNORE_PATTERNS); +const generateId = () => Math.random().toString(36).substring(2, 15); + +interface GitCloneButtonProps { + className?: string; + importChat?: (description: string, messages: Message[]) => Promise; +} + +export default function GitCloneButton({ importChat }: GitCloneButtonProps) { const { ready, gitClone } = useGit(); const onClick = async (_e: any) => { if (!ready) { @@ -11,20 +40,59 @@ export default function GitCloneButton() { const repoUrl = prompt('Enter the Git url'); if (repoUrl) { - await gitClone(repoUrl); + const { workdir, data } = await gitClone(repoUrl); + + if (importChat) { + const filePaths = Object.keys(data).filter((filePath) => !ig.ignores(filePath)); + console.log(filePaths); + + const textDecoder = new TextDecoder('utf-8'); + const message: Message = { + role: 'assistant', + content: `Cloning the repo ${repoUrl} into ${workdir} + + ${filePaths + .map((filePath) => { + const { data: content, encoding } = data[filePath]; + + if (encoding === 'utf8') { + return ` +${content} +`; + } else if (content instanceof Uint8Array) { + return ` +${textDecoder.decode(content)} +`; + } else { + return ''; + } + }) + .join('\n')} + `, + id: generateId(), + createdAt: new Date(), + }; + console.log(JSON.stringify(message)); + + importChat(`Git Project:${repoUrl.split('/').slice(-1)[0]}`, [message]); + + // console.log(files); + } } }; return ( - { - onClick(e); - }} - className="w-full justify-center" - title="Clone A Git Repo" - > - Clone A Git Repo -
- + + + ); } diff --git a/app/components/chat/chatExportAndImport/ImportButtons.tsx b/app/components/chat/chatExportAndImport/ImportButtons.tsx index 2b59574..e87cd0c 100644 --- a/app/components/chat/chatExportAndImport/ImportButtons.tsx +++ b/app/components/chat/chatExportAndImport/ImportButtons.tsx @@ -5,7 +5,7 @@ import { ImportFolderButton } from '~/components/chat/ImportFolderButton'; export function ImportButtons(importChat: ((description: string, messages: Message[]) => Promise) | undefined) { return ( -
+
(); const [fs, setFs] = useState(); + const fileData = useRef>({}); const lookupSavedPassword: (url: string) => any | null = (url: string) => { try { // Save updated API keys to cookies with 30 day expiry and secure settings @@ -30,8 +32,9 @@ export function useGit() { }; useEffect(() => { webcontainerPromise.then((container) => { + fileData.current = {}; setWebcontainer(container); - setFs(getFs(container)); + setFs(getFs(container, fileData)); setReady(true); }); }, []); @@ -39,10 +42,11 @@ export function useGit() { const gitClone = useCallback( async (url: string) => { if (!webcontainer || !fs || !ready) { - return; + throw 'Webcontainer not initialized'; } - const repo = await git.clone({ + fileData.current = {}; + await git.clone({ fs, http, dir: webcontainer.workdir, @@ -51,6 +55,8 @@ export function useGit() { singleBranch: true, corsProxy: 'https://cors.isomorphic-git.org', onAuth: (url) => { + // let domain=url.split("/")[2] + let auth = lookupSavedPassword(url); if (auth) { @@ -67,8 +73,18 @@ export function useGit() { return { cancel: true }; } }, + onAuthFailure: (url, _auth) => { + toast.error(`Error Authenticating with ${url.split('/')[2]}`); + }, }); - console.log(repo); + + const data: Record = {}; + + for (const [key, value] of Object.entries(fileData.current)) { + data[key] = value; + } + + return { workdir: webcontainer.workdir, data }; }, [webcontainer], ); @@ -76,7 +92,10 @@ export function useGit() { return { ready, gitClone }; } -const getFs: (c: WebContainer) => PromiseFsClient = (webcontainer: WebContainer) => ({ +const getFs = ( + webcontainer: WebContainer, + record: MutableRefObject>, +) => ({ promises: { readFile: async (path: string, options: any) => { const encoding = options.encoding; @@ -90,6 +109,10 @@ const getFs: (c: WebContainer) => PromiseFsClient = (webcontainer: WebContainer) const relativePath = pathUtils.relative(webcontainer.workdir, path); console.log('writeFile', { relativePath, data, encoding }); + if (record.current) { + record.current[relativePath] = { data, encoding }; + } + return await webcontainer.fs.writeFile(relativePath, data, { ...options, encoding }); }, mkdir: async (path: string, options: any) => { @@ -162,7 +185,7 @@ const getFs: (c: WebContainer) => PromiseFsClient = (webcontainer: WebContainer) * For basic usage, lstat can return the same as stat * since we're not handling symbolic links */ - return await getFs(webcontainer).promises.stat(path); + return await getFs(webcontainer, record).promises.stat(path); }, readlink: async (path: string) => {