summaryrefslogtreecommitdiff
path: root/Omni/Agent/Worker.hs
diff options
context:
space:
mode:
authorBen Sima <ben@bensima.com>2025-11-30 21:30:00 -0500
committerBen Sima <ben@bensima.com>2025-11-30 21:30:00 -0500
commit9fa7697cd979eaa15a2479819463c3bdd86cc99a (patch)
tree0eee4aebe8f99608e1ff3f831797dd0214fe4ed0 /Omni/Agent/Worker.hs
parent194173619e0e1940284f4d4fa3de49f5197636c1 (diff)
Add agent observability: event logging and storage
- Add Omni/Agent/Event.hs with AgentEvent types - Add agent_events table schema and CRUD functions to Core.hs - Add new callbacks to Engine.hs: onAssistant, onToolResult, onComplete, onError - Wire event logging into Worker.hs with session tracking Events are now persisted to SQLite for each agent work session, enabling visibility into agent reasoning and tool usage. Task-Id: t-197.1 Task-Id: t-197.2 Task-Id: t-197.3
Diffstat (limited to 'Omni/Agent/Worker.hs')
-rw-r--r--Omni/Agent/Worker.hs30
1 files changed, 27 insertions, 3 deletions
diff --git a/Omni/Agent/Worker.hs b/Omni/Agent/Worker.hs
index 61c392b..1c69b15 100644
--- a/Omni/Agent/Worker.hs
+++ b/Omni/Agent/Worker.hs
@@ -243,6 +243,15 @@ runWithEngine repo task = do
-- Select model based on task complexity (simple heuristic)
let model = selectModel task
+ -- Generate session ID for event logging
+ sessionId <- TaskCore.generateSessionId
+ let tid = TaskCore.taskId task
+
+ -- Helper to log events to DB
+ let logEvent eventType content = do
+ let contentJson = TE.decodeUtf8 (BSL.toStrict (Aeson.encode content))
+ TaskCore.insertAgentEvent tid sessionId eventType contentJson
+
-- Build Engine config with callbacks
totalCostRef <- newIORef (0 :: Int)
let engineCfg =
@@ -253,11 +262,26 @@ runWithEngine repo task = do
},
Engine.engineOnCost = \tokens cost -> do
modifyIORef' totalCostRef (+ cost)
- AgentLog.log <| "Cost: " <> tshow cost <> " cents (" <> tshow tokens <> " tokens)",
+ AgentLog.log <| "Cost: " <> tshow cost <> " cents (" <> tshow tokens <> " tokens)"
+ logEvent "cost" (Aeson.object [("tokens", Aeson.toJSON tokens), ("cents", Aeson.toJSON cost)]),
Engine.engineOnActivity = \activity -> do
AgentLog.log <| "[engine] " <> activity,
- Engine.engineOnToolCall = \toolName result -> do
- AgentLog.log <| "[tool] " <> toolName <> ": " <> Text.take 100 result
+ Engine.engineOnToolCall = \toolName args -> do
+ AgentLog.log <| "[tool] " <> toolName
+ logEvent "tool_call" (Aeson.object [("tool", Aeson.toJSON toolName), ("args", Aeson.toJSON args)]),
+ Engine.engineOnAssistant = \msg -> do
+ AgentLog.log <| "[assistant] " <> Text.take 200 msg
+ logEvent "assistant" (Aeson.String msg),
+ Engine.engineOnToolResult = \toolName success output -> do
+ let statusStr = if success then "ok" else "failed"
+ AgentLog.log <| "[result] " <> toolName <> " (" <> statusStr <> "): " <> Text.take 100 output
+ logEvent "tool_result" (Aeson.object [("tool", Aeson.toJSON toolName), ("success", Aeson.toJSON success), ("output", Aeson.toJSON output)]),
+ Engine.engineOnComplete = do
+ AgentLog.log "[engine] Complete"
+ logEvent "complete" Aeson.Null,
+ Engine.engineOnError = \err -> do
+ AgentLog.log <| "[error] " <> err
+ logEvent "error" (Aeson.String err)
}
-- Build Agent config