diff options
Diffstat (limited to 'Omni/Agent/Worker.hs')
| -rw-r--r-- | Omni/Agent/Worker.hs | 81 |
1 files changed, 68 insertions, 13 deletions
diff --git a/Omni/Agent/Worker.hs b/Omni/Agent/Worker.hs index 01099a0..c01a853 100644 --- a/Omni/Agent/Worker.hs +++ b/Omni/Agent/Worker.hs @@ -5,7 +5,15 @@ module Omni.Agent.Worker where import Alpha +import Control.Concurrent (forkIO, killThread, threadDelay) +import Control.Monad (forever) +import qualified Data.Aeson as Aeson +import qualified Data.Aeson.KeyMap as KM +import qualified Data.ByteString.Lazy as BL +import qualified Data.Scientific as Scientific import qualified Data.Text as Text +import qualified Data.Text.IO as TIO +import qualified Data.Time as Time import qualified Omni.Agent.Core as Core import qualified Omni.Agent.Git as Git import qualified Omni.Agent.Log as AgentLog @@ -13,6 +21,7 @@ import qualified Omni.Task.Core as TaskCore import qualified System.Directory as Directory import qualified System.Exit as Exit import System.FilePath ((</>)) +import qualified System.IO as IO import qualified System.Process as Process start :: Core.Worker -> IO () @@ -58,7 +67,7 @@ processTask worker task = do AgentLog.updateActivity ("Claiming task " <> tid) -- Claim task - TaskCore.updateTaskStatus tid TaskCore.InProgress + TaskCore.updateTaskStatus tid TaskCore.InProgress [] -- Commit claim locally Git.commit repo ("task: claim " <> tid) @@ -87,18 +96,20 @@ processTask worker task = do -- Run Amp AgentLog.updateActivity "Running Amp agent..." - exitCode <- runAmp repo task + (exitCode, output) <- runAmp repo task case exitCode of Exit.ExitSuccess -> do AgentLog.log "Agent finished successfully" -- Update status to Review (bundled with feature commit) - TaskCore.updateTaskStatus tid TaskCore.Review + TaskCore.updateTaskStatus tid TaskCore.Review [] -- Commit changes - -- We should check if there are changes, but 'git add .' is safe. - Git.commit repo ("feat: implement " <> tid) + -- We use the agent's output as the extended commit description + let summary = Text.strip output + let commitMsg = "feat: implement " <> tid <> "\n\n" <> summary + Git.commit repo commitMsg -- Submit for review AgentLog.updateActivity "Submitting for review..." @@ -111,18 +122,17 @@ processTask worker task = do Git.syncWithLive repo -- Update status to Review (for signaling) - TaskCore.updateTaskStatus tid TaskCore.Review + TaskCore.updateTaskStatus tid TaskCore.Review [] Git.commit repo ("task: review " <> tid) - + AgentLog.log ("[✓] Task " <> tid <> " completed") AgentLog.update (\s -> s {AgentLog.statusTask = Nothing}) - Exit.ExitFailure code -> do AgentLog.log ("Agent failed with code " <> tshow code) AgentLog.updateActivity "Agent failed, retrying..." threadDelay (10 * 1000000) -- Sleep 10s -runAmp :: FilePath -> TaskCore.Task -> IO Exit.ExitCode +runAmp :: FilePath -> TaskCore.Task -> IO (Exit.ExitCode, Text) runAmp repo task = do let prompt = "You are a Worker Agent.\n" @@ -134,7 +144,8 @@ runAmp repo task = do <> "3. Run tests to verify your work (e.g., 'bild --test Omni/Namespace').\n" <> "4. Fix any errors found during testing.\n" <> "5. Do NOT update the task status or manage git branches (the system handles that).\n" - <> "6. When finished and tested, exit.\n\n" + <> "6. Do NOT run 'git commit'. The system will commit your changes automatically.\n" + <> "7. When finished and tested, exit.\n\n" <> "Context:\n" <> "- You are working in '" <> Text.pack repo @@ -144,13 +155,37 @@ runAmp repo task = do <> "'.\n" Directory.createDirectoryIfMissing True (repo </> "_/llm") + let logPath = repo </> "_/llm/amp.log" + + -- Ensure log file is empty/exists + IO.writeFile logPath "" + + -- Read AGENTS.md + agentsMd <- + fmap (fromMaybe "") <| do + exists <- Directory.doesFileExist (repo </> "AGENTS.md") + if exists + then Just </ readFile (repo </> "AGENTS.md") + else pure Nothing + + let fullPrompt = + prompt + <> "\n\nREPOSITORY GUIDELINES (AGENTS.md):\n" + <> agentsMd + + -- Monitor log file + tidLog <- forkIO (monitorLog logPath) -- Assume amp is in PATH - let args = ["--log-level", "debug", "--log-file", "_/llm/amp.log", "--dangerously-allow-all", "-x", Text.unpack prompt] + let args = ["--log-level", "debug", "--log-file", "_/llm/amp.log", "--dangerously-allow-all", "-x", Text.unpack fullPrompt] let cp = (Process.proc "amp" args) {Process.cwd = Just repo} - (_, _, _, ph) <- Process.createProcess cp - Process.waitForProcess ph + (exitCode, out, _err) <- Process.readCreateProcessWithExitCode cp "" + + -- Cleanup + killThread tidLog + + pure (exitCode, Text.pack out) formatTask :: TaskCore.Task -> Text formatTask t = @@ -202,3 +237,23 @@ findBaseBranch repo task = do case candidates of (candidate : _) -> pure ("task/" <> TaskCore.depId candidate) [] -> pure "live" + +monitorLog :: FilePath -> IO () +monitorLog path = do + -- Wait for file to exist + waitForFile path + + IO.withFile path IO.ReadMode <| \h -> do + IO.hSetBuffering h IO.LineBuffering + forever <| do + eof <- IO.hIsEOF h + if eof + then threadDelay 100000 -- 0.1s + else do + line <- TIO.hGetLine h + AgentLog.processLogLine line + +waitForFile :: FilePath -> IO () +waitForFile p = do + e <- Directory.doesFileExist p + if e then pure () else threadDelay 100000 >> waitForFile p |
