Create Trace.hs with Event and Trace Types

t-369.2·WorkTask·
·
·
·Omni/Agent.hs
Parent:t-369·Created1 month ago·Updated1 month ago

Dependencies

Description

Edit

Create Omni/Agent/Trace.hs with structured trace and event types.

Context

Traces are first-class data in the new architecture. Every operation emits events, and traces can be queried, analyzed, and used for checkpointing/replay.

This replaces the callback-based observability in Engine.hs with inspectable data.

Read Omni/Agent/ARCHITECTURE.md for full design rationale.

Deliverables

Create Omni/Agent/Trace.hs containing:

1. Event Type

data Event
  = EventInferStart
      { evModel :: Text
      , evPrompt :: Text  -- or structured Prompt type
      , evTimestamp :: UTCTime
      , evIteration :: Int
      }
  | EventInferEnd
      { evResponsePreview :: Text  -- first N chars
      , evTokens :: Int
      , evCostCents :: Double
      , evDurationMs :: Int
      , evTimestamp :: UTCTime
      , evIteration :: Int
      }
  | EventToolCall
      { evToolName :: Text
      , evToolArgs :: Value
      , evTimestamp :: UTCTime
      , evIteration :: Int
      }
  | EventToolResult
      { evToolName :: Text
      , evToolSuccess :: Bool
      , evToolOutput :: Text
      , evDurationMs :: Int
      , evTimestamp :: UTCTime
      , evIteration :: Int
      }
  | EventStateRead
      { evKey :: Text
      , evTimestamp :: UTCTime
      }
  | EventStateWrite
      { evKey :: Text
      , evTimestamp :: UTCTime
      }
  | EventFork
      { evBranchCount :: Int
      , evBranchIds :: [TraceId]
      , evTimestamp :: UTCTime
      }
  | EventJoin
      { evBranchIds :: [TraceId]
      , evTimestamp :: UTCTime
      }
  | EventCheckpoint
      { evCheckpointName :: Text
      , evTimestamp :: UTCTime
      }
  | EventLimit
      { evBudget :: Budget
      , evTimestamp :: UTCTime
      }
  | EventExhausted
      { evResource :: Text  -- "cost", "tokens", "time"
      , evTimestamp :: UTCTime
      }
  | EventSteering
      { evSteeringMessage :: Text
      , evTimestamp :: UTCTime
      }
  | EventCustom
      { evCustomType :: Text
      , evCustomData :: Value
      , evTimestamp :: UTCTime
      }
  deriving (Show, Eq, Generic)

instance ToJSON Event
instance FromJSON Event

2. TraceId Type

newtype TraceId = TraceId Text
  deriving (Show, Eq, Ord, ToJSON, FromJSON)

newTraceId :: IO TraceId  -- generate UUID-based ID

3. Trace Type

data Trace = Trace
  { traceId :: TraceId
  , traceParentId :: Maybe TraceId
  , traceStartTime :: UTCTime
  , traceEndTime :: Maybe UTCTime
  , traceEvents :: [Event]
  }
  deriving (Show, Eq, Generic)

instance ToJSON Trace
instance FromJSON Trace

-- Smart constructor
newTrace :: IO Trace
newTrace = do
  tid <- newTraceId
  now <- getCurrentTime
  pure Trace
    { traceId = tid
    , traceParentId = Nothing
    , traceStartTime = now
    , traceEndTime = Nothing
    , traceEvents = []
    }

4. Trace Operations

-- Append an event
appendEvent :: Event -> Trace -> Trace

-- Merge traces (for parallel branches)
mergeTraces :: [Trace] -> Trace

-- Query functions
totalCost :: Trace -> Double
totalTokens :: Trace -> Int
totalDuration :: Trace -> Maybe NominalDiffTime
toolCalls :: Trace -> [(Text, Value, Value, Int)]  -- name, args, result, duration
inferCalls :: Trace -> Int
checkpoints :: Trace -> [Text]
errors :: Trace -> [Text]

-- Filtering
eventsOfType :: Text -> Trace -> [Event]
eventsBetween :: UTCTime -> UTCTime -> Trace -> [Event]

5. Checkpoint Type

data Checkpoint = Checkpoint
  { cpName :: Text
  , cpTraceId :: TraceId
  , cpTrace :: Trace  -- events up to checkpoint
  , cpStateSnapshot :: ByteString  -- serialized state
  , cpTimestamp :: UTCTime
  }
  deriving (Show, Eq, Generic)

instance ToJSON Checkpoint
instance FromJSON Checkpoint

6. Serialization for JSONL

-- Write trace to JSONL file (one event per line)
writeTraceJsonl :: FilePath -> Trace -> IO ()

-- Read trace from JSONL file
readTraceJsonl :: FilePath -> IO (Either Text Trace)

-- Append single event to JSONL file (for streaming writes)
appendEventJsonl :: FilePath -> TraceId -> Event -> IO ()

Notes

  • Look at Engine.hs AgentEvent type - this supersedes it
  • Look at Events.hs - this supersedes it, but keep compatible JSONL format
  • Events should be lightweight - don't store full prompts/responses, just previews
  • TraceId should be human-readable like Events.hs RunId (adjective-noun)

Testing

  • Event JSON roundtrip
  • Trace JSON roundtrip
  • totalCost/totalTokens computation
  • mergeTraces preserves all events
  • JSONL write/read roundtrip

Files to Read First

  • Omni/Agent/ARCHITECTURE.md (design)
  • Omni/Agent/Engine.hs (AgentEvent type to supersede)
  • Omni/Agent/Events.hs (current implementation to supersede)

Timeline (2)

🔄[human]Open → InProgress1 month ago
🔄[human]InProgress → Done1 month ago