packages feed

shikumi-eval-0.2.0.0: test/UsageSpec.hs

-- | Usage-accounting tests for both blocking and streamed LM calls.
module UsageSpec (tests) where

import Baikai (_Context, _Model, _Options)
import Effectful (runEff)
import Effectful.Concurrent (runConcurrent)
import Effectful.Error.Static (runErrorNoCallStack)
import Effectful.Prim (runPrim)
import EvalFixtures
  ( Answer (..),
    Question (..),
    qaProg,
    runConstLLM,
    runStreamLLM,
    usageResponse,
    usageTerminalEvents,
    usageTotalsPerCall,
  )
import Shikumi.Effect.Time (runTime)
import Shikumi.Error (ShikumiError)
import Shikumi.Eval.Evaluate (evaluatePure)
import Shikumi.Eval.Metric (exactMatch)
import Shikumi.Eval.Report (Report (..), UsageTotals (..))
import Shikumi.Eval.Types (dataset, example)
import Shikumi.Eval.Usage (withUsageTotals)
import Shikumi.LLM (stream)
import Shikumi.Program (runProgram)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (assertFailure, testCase, (@?=))

tests :: TestTree
tests =
  testGroup
    "Usage"
    [ testCase "complete calls accumulate non-zero usage" $ do
        result <-
          runEff . runPrim . runErrorNoCallStack @ShikumiError $
            runConstLLM (usageResponse "yes") $
              withUsageTotals $ do
                _ <- runProgram qaProg (Question "q1")
                _ <- runProgram qaProg (Question "q2")
                pure ()
        case result of
          Left e -> assertFailure ("unexpected error: " <> show e)
          Right (_, totals) -> totals @?= usageTotalsPerCall <> usageTotalsPerCall,
      testCase "stream calls accumulate usage" $ do
        let events = usageTerminalEvents "yes"
        result <-
          runEff . runPrim $
            runStreamLLM events $
              withUsageTotals (stream _Model _Context _Options)
        snd result @?= usageTotalsPerCall,
      testCase "evaluate reports non-zero usage end-to-end" $ do
        let ds =
              dataset
                [ example (Question "q1") (Answer "yes"),
                  example (Question "q2") (Answer "yes"),
                  example (Question "q3") (Answer "yes")
                ]
        report <-
          runEff . runPrim . runTime . runConcurrent . runErrorNoCallStack @ShikumiError $
            runConstLLM (usageResponse "yes") $
              evaluatePure ds exactMatch qaProg
        case report of
          Left e -> assertFailure ("unexpected error: " <> show e)
          Right r ->
            usage r
              @?= UsageTotals
                { totalInputTokens = 300,
                  totalOutputTokens = 60,
                  totalTokens = 360,
                  totalCostUsd = 3 / 1000
                }
    ]