Update Agentd to run Op programs in containers.
Agentd runs agent specs in Docker containers. Update it to support Op programs, with the interpreter running inside the container.
Add Op-native spec format alongside markdown:
# agent-spec.yaml
kind: op
program: Omni.Agent.Programs.Coder.coder # Haskell module path
config:
namespace: Biz/Cloud
task: "Fix the bug"
model: claude-sonnet-4
interpreter: sequential # or: parallel
state: crdt # or: stm, event-log
sandbox:
image: agent-haskell
workspace: /workspace
budget:
cost_cents: 100
tokens: 100000
timeout_sec: 600
-- | Parse Op spec
data OpSpec = OpSpec
{ opProgram :: Text -- module path to Op program
, opConfig :: Value -- config JSON passed to program
, opInterpreter :: Interpreter
, opState :: StateStrategy
, opSandbox :: Sandbox
, opBudget :: Budget
}
data Interpreter = Sequential | Parallel | Distributed
data StateStrategy = CRDT | STM | EventLog
parseOpSpec :: Text -> Either Text OpSpec
-- | Run Op spec in container
runOpSpec :: OpSpec -> IO Exit.ExitCode
runOpSpec spec = do
-- Build docker command
let dockerArgs =
[ "run", "--rm", "-i"
, "-v", workspace <> ":/workspace"
, "-w", "/workspace"
, image spec
-- Run interpreter with program
, "op-runner"
, "--program", Text.unpack (opProgram spec)
, "--config", Text.unpack (encodeConfig (opConfig spec))
, "--interpreter", show (opInterpreter spec)
, "--state", show (opState spec)
]
...
Create Omni/Agent/OpRunner.hs:
-- | Runner binary for Op programs inside containers
-- : out op-runner
module Omni.Agent.OpRunner where
main :: IO ()
main = do
args <- parseArgs
-- Load program (this is the tricky part)
-- Option 1: Compile program into runner
-- Option 2: Use hint/plugins to load dynamically
-- Option 3: Serialize Op programs
-- For now, hardcode known programs
program <- case argProgram args of
"Omni.Agent.Programs.Agent" ->
pure (Agent.agent (decodeConfig (argConfig args)))
"Omni.Agent.Programs.Coder" ->
pure (Coder.coder (decodeConfig (argConfig args)))
other ->
die ("Unknown program: " <> other)
-- Select interpreter
interpreter <- case argInterpreter args of
Sequential -> pure runSequential
Parallel -> pure runParallel
-- Run
result <- interpreter config initialState program
-- Output result
case result of
Left err -> do
hPutStrLn stderr err
exitFailure
Right (a, trace, _) -> do
-- Write trace to workspace
writeTraceJsonl "/workspace/_/trace.jsonl" trace
-- Output result
BL.putStrLn (encode a)
Add op-runner to container images:
# Omni/Agentd/Images/Base.nix
buildImage {
contents = [
op-runner
# ... existing tools
];
}
agentd run spec.yaml # runs markdown or op spec
agentd run --op program.hs # runs Op program directly