From be32ee30dacc65406c1e949765786446345f37b2 Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Thu, 27 Nov 2025 14:14:40 -0500 Subject: Add human notes field for intervention tasks All tests pass. Let me summarize the implementation: I've added a human notes field for intervention tasks with the following 1. **Omni/Task/Core.hs**: - Added `retryNotes :: Maybe Text` field to `RetryContext` data type - Added `notes` column to `retryContextColumns` for schema migration - Updated `getRetryContext` to fetch the notes field from DB - Updated `setRetryContext` to save the notes field to DB - Updated `getAllRetryContexts` to include notes - Added `updateRetryNotes :: Text -> Text -> IO ()` function to updat 2. **Omni/Jr/Web.hs**: - Added new API endpoint: `POST /tasks/:id/notes` - Added `NotesForm` type and `FromForm` instance - Added `taskNotesHandler` to save notes - Updated `renderRetryContextBanner` to accept task ID and display: - Notes textarea form when max retries exceeded (intervention tasks - Existing notes display for non-critical retry banners 3. **Omni/Agent/Worker.hs**: - Updated worker prompt to include human notes/guidance in the retry - Preserved existing notes when setting new retry context 4. **Omni/Jr.hs**: - Updated all `RetryContext` creations to preserve existing notes Task-Id: t-153.5 --- Omni/Task/Core.hs | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) (limited to 'Omni/Task/Core.hs') diff --git a/Omni/Task/Core.hs b/Omni/Task/Core.hs index 5af4ce4..4eac9b5 100644 --- a/Omni/Task/Core.hs +++ b/Omni/Task/Core.hs @@ -78,7 +78,8 @@ data RetryContext = RetryContext retryOriginalCommit :: Text, retryConflictFiles :: [Text], retryAttempt :: Int, - retryReason :: Text -- "merge_conflict" | "ci_failure" | "rejected" + retryReason :: Text, -- "merge_conflict" | "ci_failure" | "rejected" + retryNotes :: Maybe Text -- Human notes/guidance for intervention } deriving (Show, Eq, Generic) @@ -422,7 +423,8 @@ retryContextColumns = ("original_commit", "TEXT"), ("conflict_files", "TEXT"), ("attempt", "INTEGER"), - ("reason", "TEXT") + ("reason", "TEXT"), + ("notes", "TEXT") ] -- | Migrate a table by adding any missing columns @@ -1047,21 +1049,22 @@ getRetryContext tid = rows <- SQL.query conn - "SELECT task_id, original_commit, conflict_files, attempt, reason FROM retry_context WHERE task_id = ?" + "SELECT task_id, original_commit, conflict_files, attempt, reason, notes FROM retry_context WHERE task_id = ?" (SQL.Only tid) :: - IO [(Text, Text, Text, Int, Text)] + IO [(Text, Text, Text, Int, Text, Maybe Text)] case rows of [] -> pure Nothing - ((taskId, commit, filesJson, attempt, reason) : _) -> + ((taskId', commit, filesJson, attempt, reason, notes) : _) -> let files = fromMaybe [] (decode (BLC.pack <| T.unpack filesJson)) in pure <| Just RetryContext - { retryTaskId = taskId, + { retryTaskId = taskId', retryOriginalCommit = commit, retryConflictFiles = files, retryAttempt = attempt, - retryReason = reason + retryReason = reason, + retryNotes = notes } -- | Set retry context for a task (upsert) @@ -1071,8 +1074,8 @@ setRetryContext ctx = let filesJson = T.pack <| BLC.unpack <| encode (retryConflictFiles ctx) SQL.execute conn - "INSERT OR REPLACE INTO retry_context (task_id, original_commit, conflict_files, attempt, reason) VALUES (?, ?, ?, ?, ?)" - (retryTaskId ctx, retryOriginalCommit ctx, filesJson, retryAttempt ctx, retryReason ctx) + "INSERT OR REPLACE INTO retry_context (task_id, original_commit, conflict_files, attempt, reason, notes) VALUES (?, ?, ?, ?, ?, ?)" + (retryTaskId ctx, retryOriginalCommit ctx, filesJson, retryAttempt ctx, retryReason ctx, retryNotes ctx) -- | Clear retry context for a task (on successful merge) clearRetryContext :: Text -> IO () @@ -1173,15 +1176,34 @@ getAllRetryContexts = rows <- SQL.query_ conn - "SELECT task_id, original_commit, conflict_files, attempt, reason FROM retry_context" :: - IO [(Text, Text, Text, Int, Text)] + "SELECT task_id, original_commit, conflict_files, attempt, reason, notes FROM retry_context" :: + IO [(Text, Text, Text, Int, Text, Maybe Text)] pure [ RetryContext { retryTaskId = tid, retryOriginalCommit = commit, retryConflictFiles = fromMaybe [] (decode (BLC.pack (T.unpack filesJson))), retryAttempt = attempt, - retryReason = reason + retryReason = reason, + retryNotes = notes } - | (tid, commit, filesJson, attempt, reason) <- rows + | (tid, commit, filesJson, attempt, reason, notes) <- rows ] + +-- | Update just the notes field for a retry context +updateRetryNotes :: Text -> Text -> IO () +updateRetryNotes tid notes = do + maybeCtx <- getRetryContext tid + case maybeCtx of + Nothing -> + setRetryContext + RetryContext + { retryTaskId = tid, + retryOriginalCommit = "", + retryConflictFiles = [], + retryAttempt = 0, + retryReason = "", + retryNotes = Just notes + } + Just ctx -> + setRetryContext ctx {retryNotes = Just notes} -- cgit v1.2.3