mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-12-27 19:14:52 +03:00
Implemented first version of CodeAgent monad.
This commit is contained in:
parent
65ec766ad6
commit
4401d4a89f
53
waspc/cli/src/Wasp/Cli/Command/AI/CodeAgent.hs
Normal file
53
waspc/cli/src/Wasp/Cli/Command/AI/CodeAgent.hs
Normal file
@ -0,0 +1,53 @@
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
|
||||
module Wasp.Cli.Command.AI.CodeAgent
|
||||
( CodeAgent,
|
||||
CodeAgentConfig (..),
|
||||
runCodeAgent,
|
||||
writeToLog,
|
||||
writeToFile,
|
||||
getFile,
|
||||
getAllFiles,
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Monad.IO.Class (MonadIO (liftIO))
|
||||
import Control.Monad.Reader (MonadReader, ReaderT (runReaderT), asks)
|
||||
import Control.Monad.State (MonadState, StateT (runStateT), gets)
|
||||
import Data.List (find)
|
||||
import Data.Text (Text)
|
||||
import Wasp.OpenAI (OpenAIApiKey)
|
||||
|
||||
newtype CodeAgent a = CodeAgent {_unCodeAgent :: ReaderT CodeAgentConfig (StateT CodeAgentState IO) a}
|
||||
deriving (Monad, Applicative, Functor, MonadIO, MonadReader CodeAgentConfig, MonadState CodeAgentState)
|
||||
|
||||
data CodeAgentConfig = CodeAgentConfig
|
||||
{ _openAIApiKey :: !OpenAIApiKey,
|
||||
_writeFile :: !(FilePath -> Text -> IO ()), -- TODO: Use StrongPath? Not clear which kind of path is it, rel, abs, ... .
|
||||
_writeLog :: !(Text -> IO ())
|
||||
}
|
||||
|
||||
runCodeAgent :: CodeAgent a -> CodeAgentConfig -> IO a
|
||||
runCodeAgent codeAgent config =
|
||||
fst <$> (_unCodeAgent codeAgent `runReaderT` config) `runStateT` initialState
|
||||
where
|
||||
initialState = CodeAgentState {_files = []}
|
||||
|
||||
writeToLog :: Text -> CodeAgent ()
|
||||
writeToLog msg = asks _writeLog >>= liftIO . ($ msg)
|
||||
|
||||
writeToFile :: FilePath -> (Maybe Text -> Text) -> CodeAgent ()
|
||||
writeToFile path updateContentFn = do
|
||||
content <- updateContentFn <$> getFile path
|
||||
asks _writeFile >>= liftIO . ($ content) . ($ path)
|
||||
|
||||
getFile :: FilePath -> CodeAgent (Maybe Text)
|
||||
getFile path =
|
||||
(snd <$>) . find ((== path) . fst) <$> getAllFiles
|
||||
|
||||
getAllFiles :: CodeAgent [(FilePath, Text)]
|
||||
getAllFiles = gets _files
|
||||
|
||||
data CodeAgentState = CodeAgentState
|
||||
{ _files :: ![(FilePath, Text)]
|
||||
}
|
@ -3,7 +3,6 @@ module Wasp.Cli.Command.AI.GenerateNewProject () where
|
||||
-- TODO: Probably move this module out of here into general wasp lib.
|
||||
|
||||
import Wasp.OpenAI (OpenAIApiKey)
|
||||
import qualified Wasp.OpenAI.ChatGPT as Chat
|
||||
|
||||
data NewProjectDetails = NewProjectDetails
|
||||
{ _projectName :: !String,
|
||||
@ -13,13 +12,11 @@ data NewProjectDetails = NewProjectDetails
|
||||
|
||||
data AuthProvider = Google
|
||||
|
||||
data FileDraft = FileDraft
|
||||
{ path :: FilePath, -- TODO: Use StrongPath?
|
||||
content :: Text
|
||||
}
|
||||
|
||||
-- TODO: Create a monad stack transformer that contains openaiapikey + has state which holds files to generate?
|
||||
-- Call it CodeGenerator. It can also send messages (via Chan) about its progress.
|
||||
-- It doesn't even need to know how to send messages, it can just do that via IO somehow, and then we inject logic for that, be it Chan or something else.
|
||||
-- But we define messages.
|
||||
-- We could have two functions: writeFile, and updateFile. Or maybe just writeFile is enough, but it accepts previous content, if it has any.
|
||||
|
||||
-- TODO: Have generateNewProject accept Chan, to which it will stream its progress?
|
||||
-- It could just stream its output instead of printing it to stdout, so calling function
|
||||
@ -49,4 +46,5 @@ generateNewProject openAiKey newProjectDetails = do
|
||||
-- TODO: Same as actions.
|
||||
pages <- generatePages newProjectDetails plan entities queries actions
|
||||
-- TODO: Similar as actions.
|
||||
-- TODO: what about having additional step here that goes through all the files once again and fixes any stuff in them (Wasp, JS files)? REPL?
|
||||
return ()
|
||||
|
@ -10,6 +10,7 @@ module Wasp.Util.IO
|
||||
readFileStrict,
|
||||
writeFile,
|
||||
removeFile,
|
||||
tryReadFile,
|
||||
)
|
||||
where
|
||||
|
||||
@ -17,6 +18,7 @@ import Control.Monad (filterM, when)
|
||||
import Control.Monad.Extra (whenM)
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text.IO as T.IO
|
||||
import qualified Data.Text.IO as Text.IO
|
||||
import StrongPath (Abs, Dir, Dir', File, Path', Rel, basename, parseRelDir, parseRelFile, toFilePath, (</>))
|
||||
import qualified StrongPath as SP
|
||||
import qualified System.Directory as SD
|
||||
@ -101,3 +103,12 @@ writeFile = P.writeFile . SP.fromAbsFile
|
||||
|
||||
removeFile :: Path' Abs (File f) -> IO ()
|
||||
removeFile = SD.removeFile . SP.fromAbsFile
|
||||
|
||||
tryReadFile :: FilePath -> IO (Maybe Text)
|
||||
tryReadFile fp =
|
||||
(Just <$> Text.IO.readFile fp)
|
||||
`catch` ( \e ->
|
||||
if isDoesNotExistError e
|
||||
then return Nothing
|
||||
else throwIO e
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user