← Back to task

Commit f151fbf7

commit f151fbf764670369c54d2b9c03a5d1c8c1bb82fb
Author: Ben Sima <ben@bensima.com>
Date:   Thu Nov 27 09:55:55 2025

    Add logActivity helper and integrate into Worker.hs
    
    Implementation complete. The task is done:
    
    1. **Created `logActivity` helper** in `Omni/Task/Core.hs` that writes
    t 2. **Integrated into Worker.hs** at all key points:
       - `Claiming` - when claiming task - `Running` - when starting amp
       - `Reviewing` - when amp completes successfully - `Retrying` -
       on retry (includes attempt count in metadata) - `Completed` - on
       success (includes result type in metadata) - `Failed` - on failure
       (includes exit code or reason in metadata)
    
    Task-Id: t-148.2

diff --git a/Omni/Agent/Worker.hs b/Omni/Agent/Worker.hs
index 0bf75194..2c603a96 100644
--- a/Omni/Agent/Worker.hs
+++ b/Omni/Agent/Worker.hs
@@ -4,7 +4,10 @@
 module Omni.Agent.Worker where
 
 import Alpha
+import qualified Data.Aeson as Aeson
+import qualified Data.ByteString.Lazy as BSL
 import qualified Data.Text as Text
+import qualified Data.Text.Encoding as TE
 import qualified Data.Text.IO as TIO
 import qualified Omni.Agent.Core as Core
 import qualified Omni.Agent.Log as AgentLog
@@ -34,6 +37,12 @@ logMsg worker msg =
     then putText msg
     else AgentLog.log msg
 
+-- | Convert key-value pairs to JSON metadata string
+toMetadata :: [(Text, Text)] -> Text
+toMetadata pairs =
+  let obj = Aeson.object [(k, Aeson.String v) | (k, v) <- pairs]
+   in TE.decodeUtf8 (BSL.toStrict (Aeson.encode obj))
+
 runOnce :: Core.Worker -> Maybe Text -> IO ()
 runOnce worker maybeTaskId = do
   -- Find work
@@ -69,16 +78,19 @@ processTask worker task = do
   say ("[worker] Claiming task " <> tid)
 
   -- Claim task
+  TaskCore.logActivity tid TaskCore.Claiming Nothing
   TaskCore.updateTaskStatus tid TaskCore.InProgress []
   say "[worker] Status -> InProgress"
 
   -- Run Amp
   say "[worker] Starting amp..."
+  TaskCore.logActivity tid TaskCore.Running Nothing
   (exitCode, output) <- runAmp repo task
   say ("[worker] Amp exited with: " <> tshow exitCode)
 
   case exitCode of
     Exit.ExitSuccess -> do
+      TaskCore.logActivity tid TaskCore.Reviewing Nothing
       say "[worker] Running formatters..."
       _ <- runFormatters repo
 
@@ -98,6 +110,7 @@ processTask worker task = do
           if attempt > 3
             then do
               say "[worker] Task failed 3 times, needs human intervention"
+              TaskCore.logActivity tid TaskCore.Failed (Just (toMetadata [("reason", "max_retries_exceeded")]))
               TaskCore.updateTaskStatus tid TaskCore.Open []
             else do
               TaskCore.setRetryContext
@@ -108,22 +121,26 @@ processTask worker task = do
                     TaskCore.retryAttempt = attempt,
                     TaskCore.retryReason = "commit_failed: " <> commitErr
                   }
+              TaskCore.logActivity tid TaskCore.Retrying (Just (toMetadata [("attempt", tshow attempt)]))
               TaskCore.updateTaskStatus tid TaskCore.Open []
               say ("[worker] Task reopened (attempt " <> tshow attempt <> "/3)")
         NoChanges -> do
           -- No changes = task already implemented, mark as Done
           say "[worker] No changes to commit - task already done"
           TaskCore.clearRetryContext tid
+          TaskCore.logActivity tid TaskCore.Completed (Just (toMetadata [("result", "no_changes")]))
           TaskCore.updateTaskStatus tid TaskCore.Done []
           say ("[worker] ✓ Task " <> tid <> " -> Done (no changes)")
           unless quiet <| AgentLog.update (\s -> s {AgentLog.statusTask = Nothing})
         CommitSuccess -> do
           -- Commit succeeded, set to Review
+          TaskCore.logActivity tid TaskCore.Completed (Just (toMetadata [("result", "committed")]))
           TaskCore.updateTaskStatus tid TaskCore.Review []
           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)
+      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)"
 
diff --git a/Omni/Task/Core.hs b/Omni/Task/Core.hs
index 3a5dd492..d9ea98ca 100644
--- a/Omni/Task/Core.hs
+++ b/Omni/Task/Core.hs
@@ -1005,3 +1005,12 @@ incrementRetryAttempt tid = do
       let newAttempt = retryAttempt ctx + 1
       setRetryContext ctx {retryAttempt = newAttempt}
       pure newAttempt
+
+-- | Log activity to the task_activity table
+logActivity :: Text -> ActivityStage -> Maybe Text -> IO ()
+logActivity tid stage metadata =
+  withDb <| \conn ->
+    SQL.execute
+      conn
+      "INSERT INTO task_activity (task_id, stage, message, metadata) VALUES (?, ?, ?, ?)"
+      (tid, show stage, Nothing :: Maybe Text, metadata)