diff options
| author | Omni Worker <bot@omni.agent> | 2025-11-21 05:24:19 -0500 |
|---|---|---|
| committer | Omni Worker <bot@omni.agent> | 2025-11-21 05:24:19 -0500 |
| commit | 04f82d52994b409cfcca0dcf6afce609238fea01 (patch) | |
| tree | 2c743671fcc4dff0b952f318ca6370e9555ac76b /Omni/Agent | |
| parent | c3ab8403df5e5ed99e6769dcdc152408d57026a7 (diff) | |
task: t-rWa5yilwM.2 done (Omni.Agent.Worker)
Amp-Thread-ID:
https://ampcode.com/threads/T-7109f8d0-feb4-4a24-bc4b-37743227e2cb
Co-authored-by: Amp <amp@ampcode.com>
Diffstat (limited to 'Omni/Agent')
| -rw-r--r-- | Omni/Agent/Git.hs | 6 | ||||
| -rw-r--r-- | Omni/Agent/Worker.hs | 108 |
2 files changed, 67 insertions, 47 deletions
diff --git a/Omni/Agent/Git.hs b/Omni/Agent/Git.hs index 7ee8a16..cf9a122 100644 --- a/Omni/Agent/Git.hs +++ b/Omni/Agent/Git.hs @@ -144,10 +144,10 @@ git dir args = do syncWithLive :: FilePath -> IO () syncWithLive repo = do Log.info ["git", "syncing with live"] - git repo ["fetch", "origin", "live"] - + -- git repo ["fetch", "origin", "live"] -- Optional + -- Try rebase, if fail, abort - let cmd = (Process.proc "git" ["rebase", "origin/live"]) {Process.cwd = Just repo} + let cmd = (Process.proc "git" ["rebase", "live"]) {Process.cwd = Just repo} (code, _, err) <- Process.readCreateProcessWithExitCode cmd "" case code of Exit.ExitSuccess -> pure () diff --git a/Omni/Agent/Worker.hs b/Omni/Agent/Worker.hs index be971cf..511f309 100644 --- a/Omni/Agent/Worker.hs +++ b/Omni/Agent/Worker.hs @@ -11,9 +11,9 @@ import qualified Omni.Agent.Git as Git import qualified Omni.Log as Log import qualified Omni.Task.Core as TaskCore import qualified System.Directory as Directory -import qualified System.Process as Process import qualified System.Exit as Exit import System.FilePath ((</>)) +import qualified System.Process as Process start :: Core.Worker -> IO () start worker = do @@ -23,20 +23,20 @@ start worker = do loop :: Core.Worker -> IO () loop worker = do let repo = Core.workerPath worker - + Log.info ["worker", "syncing tasks"] -- Sync with live first to get latest code and tasks -- We ignore errors here to keep the loop alive, but syncWithLive panics on conflict. -- Ideally we should catch exceptions, but for now let it fail and restart (via supervisor or manual). Git.syncWithLive repo - + -- Sync tasks database (import from live) -- Since we rebased, .tasks/tasks.jsonl should be up to date with live. -- But we might need to consolidate if there are merge artifacts (not likely with rebase). -- The bash script calls ./Omni/Agent/sync-tasks.sh which calls 'task import'. -- Here we rely on 'task loadTasks' reading the file. -- But 'syncWithLive' already updated the file from git. - + -- Find ready work readyTasks <- TaskCore.getReadyTasks case readyTasks of @@ -44,7 +44,6 @@ loop worker = do Log.info ["worker", "no work found, sleeping"] threadDelay (60 * 1000000) -- 60 seconds loop worker - (task : _) -> do processTask worker task loop worker @@ -53,87 +52,108 @@ processTask :: Core.Worker -> TaskCore.Task -> IO () processTask worker task = do let repo = Core.workerPath worker let tid = TaskCore.taskId task - + Log.info ["worker", "claiming task", tid] - + -- Claim task TaskCore.updateTaskStatus tid TaskCore.InProgress - + -- Commit claim locally Git.commit repo ("task: claim " <> tid) - + -- Prepare branch let taskBranch = "task/" <> tid currentBranch <- Git.getCurrentBranch repo if currentBranch == taskBranch then Log.info ["worker", "resuming branch", taskBranch] else Git.createBranch repo taskBranch - + -- Run Amp exitCode <- runAmp repo task - + case exitCode of Exit.ExitSuccess -> do Log.info ["worker", "agent finished successfully"] - + + -- Update status to Review (bundled with feature commit) + 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) - + -- Submit for review Log.info ["worker", "submitting for review"] - + -- Switch back to worker base let base = Core.workerName worker Git.checkout repo base - + -- Sync again Git.syncWithLive repo - - -- Update status to Review + + -- Update status to Review (for signaling) TaskCore.updateTaskStatus tid TaskCore.Review Git.commit repo ("task: review " <> tid) - Exit.ExitFailure code -> do Log.warn ["worker", "agent failed with code", Text.pack (show code)] threadDelay (10 * 1000000) -- Sleep 10s runAmp :: FilePath -> TaskCore.Task -> IO Exit.ExitCode runAmp repo task = do - let prompt = "You are a Worker Agent.\n" - <> "Your goal is to implement the following task:\n\n" - <> formatTask task - <> "\n\nINSTRUCTIONS:\n" - <> "1. Analyze the codebase (use finder/Grep) to understand where to make changes.\n" - <> "2. Implement the changes by editing files.\n" - <> "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" - <> "Context:\n" - <> "- You are working in '" <> Text.pack repo <> "'.\n" - <> "- The task is in namespace '" <> maybe "root" (\x -> x) (TaskCore.taskNamespace task) <> "'.\n" - + let prompt = + "You are a Worker Agent.\n" + <> "Your goal is to implement the following task:\n\n" + <> formatTask task + <> "\n\nINSTRUCTIONS:\n" + <> "1. Analyze the codebase (use finder/Grep) to understand where to make changes.\n" + <> "2. Implement the changes by editing files.\n" + <> "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" + <> "Context:\n" + <> "- You are working in '" + <> Text.pack repo + <> "'.\n" + <> "- The task is in namespace '" + <> fromMaybe "root" (TaskCore.taskNamespace task) + <> "'.\n" + Directory.createDirectoryIfMissing True (repo </> "_/llm") - + -- Assume amp is in PATH let args = ["--log-level", "debug", "--log-file", "_/llm/amp.log", "--dangerously-allow-all", "-x", Text.unpack prompt] - + let cp = (Process.proc "amp" args) {Process.cwd = Just repo} (_, _, _, ph) <- Process.createProcess cp Process.waitForProcess ph formatTask :: TaskCore.Task -> Text formatTask t = - "Task: " <> TaskCore.taskId t <> "\n" - <> "Title: " <> TaskCore.taskTitle t <> "\n" - <> "Type: " <> Text.pack (show (TaskCore.taskType t)) <> "\n" - <> "Status: " <> Text.pack (show (TaskCore.taskStatus t)) <> "\n" - <> "Priority: " <> Text.pack (show (TaskCore.taskPriority t)) <> "\n" - <> maybe "" (\p -> "Parent: " <> p <> "\n") (TaskCore.taskParent t) - <> maybe "" (\ns -> "Namespace: " <> ns <> "\n") (TaskCore.taskNamespace t) - <> "Created: " <> Text.pack (show (TaskCore.taskCreatedAt t)) <> "\n" - <> "Updated: " <> Text.pack (show (TaskCore.taskUpdatedAt t)) <> "\n" - <> (if null (TaskCore.taskDependencies t) then "" else "\nDependencies:\n" <> Text.unlines (map formatDep (TaskCore.taskDependencies t))) + "Task: " + <> TaskCore.taskId t + <> "\n" + <> "Title: " + <> TaskCore.taskTitle t + <> "\n" + <> "Type: " + <> Text.pack (show (TaskCore.taskType t)) + <> "\n" + <> "Status: " + <> Text.pack (show (TaskCore.taskStatus t)) + <> "\n" + <> "Priority: " + <> Text.pack (show (TaskCore.taskPriority t)) + <> "\n" + <> maybe "" (\p -> "Parent: " <> p <> "\n") (TaskCore.taskParent t) + <> maybe "" (\ns -> "Namespace: " <> ns <> "\n") (TaskCore.taskNamespace t) + <> "Created: " + <> Text.pack (show (TaskCore.taskCreatedAt t)) + <> "\n" + <> "Updated: " + <> Text.pack (show (TaskCore.taskUpdatedAt t)) + <> "\n" + <> (if null (TaskCore.taskDependencies t) then "" else "\nDependencies:\n" <> Text.unlines (map formatDep (TaskCore.taskDependencies t))) where formatDep dep = " - " <> TaskCore.depId dep <> " [" <> Text.pack (show (TaskCore.depType dep)) <> "]" |
