diff options
| author | Ben Sima <ben@bensima.com> | 2025-11-30 00:36:51 -0500 |
|---|---|---|
| committer | Ben Sima <ben@bensima.com> | 2025-11-30 00:36:51 -0500 |
| commit | 5fbcd92ff85bc9cc0b752888f6d3498aafea0b2a (patch) | |
| tree | 4bcae7c97bf81ecae696744cfcd84520e5db639d /Omni/Agent/Worker.hs | |
| parent | d05ca4732710dd9cef7fffd998a03615ad2cb58c (diff) | |
Remove amp dependency entirely
The build and tests pass. Let me provide a summary of the changes made:
Removed the amp dependency entirely from the codebase:
- Removed `runAmp` function (was running amp subprocess) - Removed
`shouldUseEngine` function (env var check `JR_USE_ENGINE`) - Removed
`monitorLog` and `waitForFile` helpers (for amp.log parsing) - Removed
unused imports: `System.IO`, `Data.Text.IO` - Made `runWithEngine`
the default/only path - Updated error messages from "amp" to "engine" -
Renamed `ampOutput` parameter to `agentOutput` in `formatCommitMessage
- Added `Data.IORef` import for `newIORef`, `modifyIORef'`, `readIORef`
- Removed amp.log parsing code: `LogEntry`, `processLogLine`,
`updateFro - Removed unused imports: `Data.Aeson`,
`Data.ByteString.Lazy`, `Data.Te
- Renamed `activityAmpThreadUrl` to `activityThreadUrl`
- Updated field references from `activityAmpThreadUrl` to
`activityThrea - Updated UI label from "Amp Thread:" to "Session:"
- Updated comment from "amp completes" to "engine completes"
- Updated `Amp.execute` to `Engine.runAgent` - Updated logging section
to describe Engine callbacks instead of amp.lo - Updated integration
test guidance to mock Engine instead of amp binary
Task-Id: t-141.6
Diffstat (limited to 'Omni/Agent/Worker.hs')
| -rw-r--r-- | Omni/Agent/Worker.hs | 180 |
1 files changed, 10 insertions, 170 deletions
diff --git a/Omni/Agent/Worker.hs b/Omni/Agent/Worker.hs index aa7c5ab..ded4144 100644 --- a/Omni/Agent/Worker.hs +++ b/Omni/Agent/Worker.hs @@ -7,10 +7,10 @@ import Alpha import qualified Data.Aeson as Aeson import qualified Data.Aeson.Key as AesonKey import qualified Data.ByteString.Lazy as BSL +import Data.IORef (modifyIORef', newIORef, readIORef) import qualified Data.List as List import qualified Data.Text as Text import qualified Data.Text.Encoding as TE -import qualified Data.Text.IO as TIO import qualified Data.Time import qualified Omni.Agent.Core as Core import qualified Omni.Agent.Engine as Engine @@ -22,7 +22,6 @@ import qualified System.Directory as Directory import qualified System.Environment as Env import qualified System.Exit as Exit import System.FilePath ((</>)) -import qualified System.IO as IO import qualified System.Process as Process start :: Core.Worker -> Maybe Text -> IO () @@ -89,38 +88,18 @@ processTask worker task = do TaskCore.updateTaskStatus tid TaskCore.InProgress [] say "[worker] Status -> InProgress" - -- Check if we should use native engine - useEngine <- shouldUseEngine - -- Run agent with timing startTime <- Data.Time.getCurrentTime activityId <- TaskCore.logActivityWithMetrics tid TaskCore.Running Nothing Nothing (Just startTime) Nothing Nothing Nothing - (exitCode, output, maybeCost) <- - if useEngine - then do - say "[worker] Starting native engine..." - (code, out, cost) <- runWithEngine repo task - pure (code, out, Just cost) - else do - say "[worker] Starting amp..." - (code, out) <- runAmp repo task - pure (code, out, Nothing) + say "[worker] Starting engine..." + (exitCode, output, costCents) <- runWithEngine repo task endTime <- Data.Time.getCurrentTime say ("[worker] Agent exited with: " <> tshow exitCode) - -- Capture metrics - from engine result or agent log - (threadUrl, costCents) <- case maybeCost of - Just engineCost -> pure (Nothing, Just engineCost) - Nothing -> do - status <- AgentLog.getStatus - let url = ("https://ampcode.com/threads/" <>) </ AgentLog.statusThread status - let cost = Just <| floor (AgentLog.statusCredits status * 100) - pure (url, cost) - -- Update the activity record with metrics - TaskCore.updateActivityMetrics activityId threadUrl (Just endTime) costCents Nothing + TaskCore.updateActivityMetrics activityId Nothing (Just endTime) (Just costCents) Nothing case exitCode of Exit.ExitSuccess -> do @@ -178,10 +157,10 @@ processTask worker task = do say ("[worker] ✓ Task " <> tid <> " -> Review") unless quiet <| AgentLog.update (\s -> s {AgentLog.statusTask = Nothing}) Exit.ExitFailure code -> do - say ("[worker] Amp failed with code " <> tshow code) + say ("[worker] Engine failed with code " <> tshow code) TaskCore.logActivity tid TaskCore.Failed (Just (toMetadata [("exit_code", tshow code)])) -- Don't set back to Open here - leave in InProgress for debugging - say "[worker] Task left in InProgress (amp failure)" + say "[worker] Task left in InProgress (engine failure)" -- | Run lint --fix to format and fix lint issues runFormatters :: FilePath -> IO (Either Text ()) @@ -218,115 +197,7 @@ tryCommit repo msg = do Exit.ExitFailure _ -> pure <| CommitFailed (Text.pack commitErr) Exit.ExitFailure c -> pure <| CommitFailed ("git diff failed with code " <> tshow c) -runAmp :: FilePath -> TaskCore.Task -> IO (Exit.ExitCode, Text) -runAmp repo task = do - -- Check for retry context - maybeRetry <- TaskCore.getRetryContext (TaskCore.taskId task) - - let ns = fromMaybe "." (TaskCore.taskNamespace task) - let basePrompt = - "You are a Worker Agent.\n" - <> "Your goal is to implement the following task:\n\n" - <> formatTask task - <> "\n\nCRITICAL INSTRUCTIONS:\n" - <> "1. Analyze the codebase to understand where to make changes.\n" - <> "2. Implement the changes by editing files.\n" - <> "3. BEFORE finishing, you MUST run: bild --test " - <> ns - <> "\n" - <> "4. Fix ALL errors from bild --test (including hlint suggestions).\n" - <> "5. Keep running bild --test until it passes with no errors.\n" - <> "6. Do NOT update task status or manage git.\n" - <> "7. Only exit after bild --test passes.\n\n" - <> "IMPORTANT: The git commit will fail if hlint finds issues.\n" - <> "You must fix hlint suggestions like:\n" - <> "- 'Use list comprehension' -> use [x | cond] instead of if/else\n" - <> "- 'Avoid lambda' -> use function composition\n" - <> "- 'Redundant bracket' -> remove unnecessary parens\n\n" - <> "Context:\n" - <> "- Working directory: " - <> Text.pack repo - <> "\n" - <> "- Namespace: " - <> ns - <> "\n" - - -- Add retry context if present - let retryPrompt = case maybeRetry of - Nothing -> "" - Just ctx -> - "\n\n## RETRY CONTEXT (IMPORTANT)\n\n" - <> "This task was previously attempted but failed. Attempt: " - <> tshow (TaskCore.retryAttempt ctx) - <> "/3\n" - <> "Reason: " - <> TaskCore.retryReason ctx - <> "\n\n" - <> ( if null (TaskCore.retryConflictFiles ctx) - then "" - else - "Conflicting files from previous attempt:\n" - <> Text.unlines (map (" - " <>) (TaskCore.retryConflictFiles ctx)) - <> "\n" - ) - <> "Original commit: " - <> TaskCore.retryOriginalCommit ctx - <> "\n\n" - <> maybe "" (\notes -> "## HUMAN NOTES/GUIDANCE\n\n" <> notes <> "\n\n") (TaskCore.retryNotes ctx) - <> "INSTRUCTIONS FOR RETRY:\n" - <> "- The codebase has changed since your last attempt\n" - <> "- Re-implement this task on top of the CURRENT codebase\n" - <> "- If there were merge conflicts, the conflicting files may have been modified by others\n" - <> "- Review the current state of those files before making changes\n" - - let prompt = basePrompt <> retryPrompt - - let logFile = repo </> "_/llm/amp.log" - - -- Read AGENTS.md - agentsMd <- - fmap (fromMaybe "") <| do - exists <- Directory.doesFileExist (repo </> "AGENTS.md") - if exists - then Just </ readFile (repo </> "AGENTS.md") - else pure Nothing - - -- Get relevant facts from the knowledge base - relevantFacts <- getRelevantFacts task - let factsSection = formatFacts relevantFacts - - let fullPrompt = - prompt - <> "\n\nREPOSITORY GUIDELINES (AGENTS.md):\n" - <> agentsMd - <> factsSection - - -- Remove old log file - exists <- Directory.doesFileExist logFile - when exists (Directory.removeFile logFile) - - Directory.createDirectoryIfMissing True (repo </> "_/llm") - - -- Assume amp is in PATH - let args = ["--try-opus", "--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, Process.std_out = Process.CreatePipe} - (_, Just hOut, _, ph) <- Process.createProcess cp - - tid <- forkIO <| monitorLog logFile ph - - exitCode <- Process.waitForProcess ph - output <- TIO.hGetContents hOut - killThread tid - pure (exitCode, output) - --- | Check if we should use native engine instead of amp subprocess -shouldUseEngine :: IO Bool -shouldUseEngine = do - env <- Env.lookupEnv "JR_USE_ENGINE" - pure <| env == Just "1" - --- | Run task using native Engine instead of amp subprocess +-- | Run task using native Engine -- Returns (ExitCode, output text, cost in cents) runWithEngine :: FilePath -> TaskCore.Task -> IO (Exit.ExitCode, Text, Int) runWithEngine repo task = do @@ -338,7 +209,7 @@ runWithEngine repo task = do -- Check for retry context maybeRetry <- TaskCore.getRetryContext (TaskCore.taskId task) - -- Build the full prompt (same as runAmp) + -- Build the full prompt let ns = fromMaybe "." (TaskCore.taskNamespace task) let basePrompt = buildBasePrompt task ns repo @@ -517,10 +388,10 @@ formatTask t = formatComment c = " [" <> Text.pack (show (TaskCore.commentCreatedAt c)) <> "] " <> TaskCore.commentText c formatCommitMessage :: TaskCore.Task -> Text -> Text -formatCommitMessage task ampOutput = +formatCommitMessage task agentOutput = let tid = TaskCore.taskId task subject = cleanSubject (TaskCore.taskTitle task) - body = cleanBody ampOutput + body = cleanBody agentOutput in if Text.null body then subject <> "\n\nTask-Id: " <> tid else subject <> "\n\n" <> body <> "\n\nTask-Id: " <> tid @@ -573,34 +444,3 @@ formatFact f = then "" else " [" <> Text.intercalate ", " (TaskCore.factRelatedFiles f) <> "]" ) - -monitorLog :: FilePath -> Process.ProcessHandle -> IO () -monitorLog path ph = do - waitForFile path - IO.withFile path IO.ReadMode <| \h -> do - IO.hSetBuffering h IO.LineBuffering - go h - where - go h = do - eof <- IO.hIsEOF h - if eof - then do - mExit <- Process.getProcessExitCode ph - case mExit of - Nothing -> do - threadDelay 100000 -- 0.1s - go h - Just _ -> pure () - else do - line <- TIO.hGetLine h - AgentLog.processLogLine line - go h - -waitForFile :: FilePath -> IO () -waitForFile path = do - exists <- Directory.doesFileExist path - if exists - then pure () - else do - threadDelay 100000 - waitForFile path |
