commit 8b07b29ecd8d8d4aa6945d0ecdfd54f4b3911d68
Author: Ben Sima <ben@bensima.com>
Date: Fri Jan 2 07:04:14 2026
Wire Coder.hs into Developer.hs, replacing pi-code.sh subprocess
Developer.runCoder now uses Omni.Ide.Coder.runCoder directly via the
Agent API, instead of spawning the pi-code.sh shell script.
Task-Id: t-278.2
diff --git a/Omni/Agent/Telegram/Developer.hs b/Omni/Agent/Telegram/Developer.hs
index 7acc1935..b27f48de 100644
--- a/Omni/Agent/Telegram/Developer.hs
+++ b/Omni/Agent/Telegram/Developer.hs
@@ -58,6 +58,7 @@ import qualified Data.Text.IO as TextIO
import qualified Data.Time as Time
import qualified Network.HTTP.Simple as HTTP
import qualified Omni.Agent.Telegram.Types as Types
+import qualified Omni.Ide.Coder as Coder
import qualified Omni.Task.Core as Task
import qualified Omni.Test as Test
import qualified System.Exit as Exit
@@ -387,40 +388,29 @@ runOrchestrator tgCfg cfg statusMsgId = do
updatePhase' PhaseReviewerApproved
pure (Right commit)
--- | Run the coder subprocess (pi-code.sh)
+-- | Run the coder using native Haskell Agent API
runCoder :: OrchestratorConfig -> IO (Either Text ())
runCoder cfg = do
- let proc =
- (Process.proc "./Omni/Ide/pi-code.sh" [Text.unpack (orchTaskId cfg)])
- { Process.cwd = Just (orchWorkDir cfg),
- -- Inherit stdout/stderr so output goes to parent (visible in logs)
- -- and we don't block on full pipe buffers
- Process.std_out = Process.Inherit,
- Process.std_err = Process.Inherit,
- -- Create new process group so we can kill children
- Process.create_group = True
+ let coderConfig =
+ Coder.defaultCoderConfig
+ { Coder.coderTaskId = orchTaskId cfg,
+ Coder.coderExtraInstructions = Nothing,
+ Coder.coderMaxIterations = 50,
+ Coder.coderMaxCostCents = 200,
+ Coder.coderVerbose = True,
+ Coder.coderOnActivity = \msg -> TextIO.hPutStrLn stdout <| "[coder] " <> msg,
+ Coder.coderOnOutput = TextIO.putStrLn
}
- (_, _, _, ph) <- Process.createProcess proc
-
- -- Register the process handle so it can be stopped
- updateOrchestratorProcess (orchChatId cfg) (Just ph)
-
- -- Wait with timeout
+ -- Run with timeout
let timeoutMicros = orchCoderTimeout cfg * 1000000
- mExit <- Timeout.timeout timeoutMicros (Process.waitForProcess ph)
-
- -- Clear the process handle
- updateOrchestratorProcess (orchChatId cfg) Nothing
+ mResult <- Timeout.timeout timeoutMicros (Coder.runCoder coderConfig)
- case mExit of
- Nothing -> do
- -- Timeout - kill process
- Process.terminateProcess ph
- pure (Left "Coder timeout")
- Just Exit.ExitSuccess -> pure (Right ())
- Just (Exit.ExitFailure code) ->
- pure (Left ("Exit code " <> tshow code))
+ case mResult of
+ Nothing -> pure (Left "Coder timeout")
+ Just (Coder.CoderSuccess _) -> pure (Right ())
+ Just (Coder.CoderError err) -> pure (Left err)
+ Just (Coder.CoderCompilationFailed err) -> pure (Left ("Compilation failed: " <> err))
-- | Run build verification (bild)
runBuild :: OrchestratorConfig -> IO (Either Text ())