From 987cd9b9adc0354ab4dbffc87a719857acce9cca Mon Sep 17 00:00:00 2001 From: Andrew Kent Date: Tue, 30 Sep 2025 08:03:07 -0600 Subject: [PATCH] rm scala code We'll add scala examples and/or scala-friendly APIs once the SDK is fully baked. --- braintrust-scala/README.md | 91 -------- braintrust-scala/build.gradle | 37 ---- .../braintrust/scala/BraintrustTracing.scala | 199 ------------------ .../dev/braintrust/scala/Evaluation.scala | 77 ------- .../scala/dev/braintrust/scala/Logger.scala | 30 --- 5 files changed, 434 deletions(-) delete mode 100644 braintrust-scala/README.md delete mode 100644 braintrust-scala/build.gradle delete mode 100644 braintrust-scala/src/main/scala/dev/braintrust/scala/BraintrustTracing.scala delete mode 100644 braintrust-scala/src/main/scala/dev/braintrust/scala/Evaluation.scala delete mode 100644 braintrust-scala/src/main/scala/dev/braintrust/scala/Logger.scala diff --git a/braintrust-scala/README.md b/braintrust-scala/README.md deleted file mode 100644 index 889b3eb..0000000 --- a/braintrust-scala/README.md +++ /dev/null @@ -1,91 +0,0 @@ -# Braintrust Scala SDK - -Scala-friendly wrappers around the Braintrust Java SDK, providing idiomatic Scala APIs while leveraging the robust Java implementation. - -## Installation - -Add to your `build.sbt`: - -```scala -libraryDependencies += "dev.braintrust" %% "braintrust-scala" % "0.1.0" -``` - -## Quick Start - -```scala -import dev.braintrust.scala._ -import scala.concurrent.ExecutionContext.Implicits.global - -// Initialize with builder DSL -val otel = BraintrustTracing.quickstart { config => - config - .withApiKey("your-api-key") - .withProjectId("my-project") - .withServiceName("my-scala-service") -} - -// Get a tracer -implicit val tracer = BraintrustTracing.getTracer(otel) - -// Use spans with automatic resource management -tracer.span("my-operation") { span => - // Your code here - span.addScore("quality", 0.95) - span.addUsage(100, 50, 0.002) -} - -// Async operations -val result = tracer.spanAsync("async-operation") { span => - Future { - // Async work - span.setAttribute("custom.attribute", "value") - "result" - } -} -``` - -## Evaluation Framework - -```scala -import dev.braintrust.scala.Evaluation - -case class QATest(question: String, expectedAnswer: String) - -val tests = Seq( - QATest("What is 2+2?", "4"), - QATest("What is the capital of France?", "Paris") -) - -// Run async evaluation -Evaluation.runAsync[QATest, String]("Q&A Evaluation")(tests) { test => - Future { - // Call your LLM here - callLLM(test.question) - } -} { (test, output) => - // Score based on whether output contains expected answer - if (output.toLowerCase.contains(test.expectedAnswer.toLowerCase)) 1.0 else 0.0 -} -``` - -## Logging - -```scala -import dev.braintrust.scala.BraintrustLogger - -BraintrustLogger.info("Starting application version={}", "1.0.0") -BraintrustLogger.debug("Processing request id={}", requestId) -BraintrustLogger.error("Failed to process", exception, "requestId={}", requestId) -``` - -## Features - -- **Idiomatic Scala API**: Uses Scala idioms like case classes, pattern matching, and futures -- **Automatic Resource Management**: Spans are automatically closed with `use` and `useAsync` -- **Type Safety**: Leverages Scala's type system for compile-time safety -- **Seamless Java Interop**: Can mix Scala and Java APIs as needed -- **Future Support**: Native support for Scala futures and async operations - -## Examples - -See the [examples directory](../examples/scala) for complete examples. \ No newline at end of file diff --git a/braintrust-scala/build.gradle b/braintrust-scala/build.gradle deleted file mode 100644 index 42ed148..0000000 --- a/braintrust-scala/build.gradle +++ /dev/null @@ -1,37 +0,0 @@ -plugins { - id 'scala' - id 'java-library' -} - -dependencies { - // Depend on the Java SDK - api project(':braintrust-java') - - // Scala library - implementation 'org.scala-lang:scala-library:2.13.12' - - // Scala-specific additions - implementation 'org.typelevel:cats-core_2.13:2.10.0' - implementation 'org.typelevel:cats-effect_2.13:3.5.2' - - // Test dependencies - testImplementation 'org.scalatest:scalatest_2.13:3.2.17' - testImplementation 'org.scalamock:scalamock_2.13:5.2.0' -} - -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 -} - -tasks.withType(ScalaCompile) { - scalaCompileOptions.additionalParameters = [ - '-feature', - '-deprecation', - '-unchecked', - '-Xlint', - '-Ywarn-dead-code', - '-Ywarn-numeric-widen', - '-Ywarn-value-discard' - ] -} \ No newline at end of file diff --git a/braintrust-scala/src/main/scala/dev/braintrust/scala/BraintrustTracing.scala b/braintrust-scala/src/main/scala/dev/braintrust/scala/BraintrustTracing.scala deleted file mode 100644 index 9983ac1..0000000 --- a/braintrust-scala/src/main/scala/dev/braintrust/scala/BraintrustTracing.scala +++ /dev/null @@ -1,199 +0,0 @@ -package dev.braintrust.scala - -import config.dev.braintrust.claude.BraintrustConfig -import dev.braintrust.trace.{BraintrustTracing => JavaTracing} -import io.opentelemetry.api.OpenTelemetry -import io.opentelemetry.api.trace.{Span, Tracer} -import scala.concurrent.{ExecutionContext, Future} -import scala.util.{Try, Success, Failure} -import scala.jdk.DurationConverters._ - -/** - * Scala-friendly API for Braintrust tracing. - * Provides idiomatic Scala wrappers around the Java SDK. - */ -object BraintrustTracing { - - /** - * Quick start with environment variables. - */ - def quickstart(): OpenTelemetry = - JavaTracing.quickstart() - - /** - * Quick start with configuration builder DSL. - * - * @example {{{ - * val otel = BraintrustTracing.quickstart { config => - * config - * .withApiKey("your-key") - * .withProjectId("my-project") - * .withServiceName("my-service") - * } - * }}} - */ - def quickstart(configure: ConfigBuilder => ConfigBuilder): OpenTelemetry = { - val builder = new ConfigBuilder() - val configured = configure(builder) - JavaTracing.quickstart(configured.build(), configured.customize) - } - - /** - * Get a tracer with Braintrust instrumentation. - */ - def getTracer(implicit otel: OpenTelemetry): Tracer = - JavaTracing.getTracer(otel) - - /** - * Configuration builder with fluent Scala API. - */ - class ConfigBuilder { - private var config = BraintrustConfig.builder() - private var tracingCustomizer: JavaTracing.Builder => Unit = _ => () - - def withApiKey(key: String): ConfigBuilder = { - config.apiKey(key) - this - } - - def withApiUrl(url: String): ConfigBuilder = { - config.apiUrl(url) - this - } - - def withProjectId(id: String): ConfigBuilder = { - config.defaultProjectId(id) - this - } - - def withDebug(enabled: Boolean = true): ConfigBuilder = { - config.debug(enabled) - this - } - - def withServiceName(name: String): ConfigBuilder = { - tracingCustomizer = { b => b.serviceName(name) } - this - } - - def withResourceAttribute(key: String, value: String): ConfigBuilder = { - val prev = tracingCustomizer - tracingCustomizer = { b => - prev(b) - b.resourceAttribute(key, value) - } - this - } - - def withExportInterval(duration: scala.concurrent.duration.Duration): ConfigBuilder = { - val prev = tracingCustomizer - tracingCustomizer = { b => - prev(b) - b.exportInterval(duration.toJava) - } - this - } - - private[scala] def build(): BraintrustConfig = config.build() - private[scala] def customize: java.util.function.Consumer[JavaTracing.Builder] = - new java.util.function.Consumer[JavaTracing.Builder] { - def accept(b: JavaTracing.Builder): Unit = tracingCustomizer(b) - } - } -} - -/** - * Implicit conversions and syntax extensions. - */ -package object scala { - - /** - * Adds Scala-friendly methods to spans. - */ - implicit class RichSpan(val span: Span) extends AnyVal { - - /** - * Execute a block within this span's scope. - */ - def use[T](block: => T): T = { - val scope = span.makeCurrent() - try { - block - } finally { - scope.close() - span.end() - } - } - - /** - * Execute an async block within this span's scope. - */ - def useAsync[T](block: => Future[T])(implicit ec: ExecutionContext): Future[T] = { - val scope = span.makeCurrent() - block.andThen { case _ => - scope.close() - span.end() - } - } - - /** - * Record a Try result and end the span. - */ - def recordResult[T](result: Try[T]): Try[T] = { - result match { - case Success(_) => - span.setStatus(io.opentelemetry.api.trace.StatusCode.OK) - case Failure(e) => - span.recordException(e) - span.setStatus(io.opentelemetry.api.trace.StatusCode.ERROR, e.getMessage) - } - span.end() - result - } - - /** - * Add a score to this span. - */ - def addScore(name: String, value: Double): Span = { - JavaTracing.SpanUtils.addScore(name, value) - span - } - - /** - * Add usage metrics to this span. - */ - def addUsage(promptTokens: Long, completionTokens: Long, cost: Double): Span = { - JavaTracing.SpanUtils.addUsageMetrics(promptTokens, completionTokens, cost) - span - } - } - - /** - * Adds Scala-friendly methods to tracers. - */ - implicit class RichTracer(val tracer: Tracer) extends AnyVal { - - /** - * Create and use a span in one call. - * - * @example {{{ - * tracer.span("operation") { span => - * // do work - * span.addScore("quality", 0.95) - * } - * }}} - */ - def span[T](name: String)(block: Span => T): T = { - val span = tracer.spanBuilder(name).startSpan() - span.use(block(span)) - } - - /** - * Create and use a span with async operation. - */ - def spanAsync[T](name: String)(block: Span => Future[T])(implicit ec: ExecutionContext): Future[T] = { - val span = tracer.spanBuilder(name).startSpan() - span.useAsync(block(span)) - } - } -} diff --git a/braintrust-scala/src/main/scala/dev/braintrust/scala/Evaluation.scala b/braintrust-scala/src/main/scala/dev/braintrust/scala/Evaluation.scala deleted file mode 100644 index 7202e5d..0000000 --- a/braintrust-scala/src/main/scala/dev/braintrust/scala/Evaluation.scala +++ /dev/null @@ -1,77 +0,0 @@ -package dev.braintrust.scala - -import dev.braintrust.eval.{Evaluation => JavaEvaluation, EvaluationConfig} -import scala.concurrent.{ExecutionContext, Future} -import scala.jdk.CollectionConverters._ -import scala.jdk.FutureConverters._ - -/** - * Scala-friendly evaluation API. - */ -object Evaluation { - - /** - * Run an evaluation with Scala futures. - * - * @example {{{ - * case class TestCase(input: String, expected: String) - * - * Evaluation.runAsync[TestCase, String]("My Eval") { test => - * Future { - * // Your async evaluation logic - * callLLM(test.input) - * } - * } { case (test, output) => - * if (output.contains(test.expected)) 1.0 else 0.0 - * } - * }}} - */ - def runAsync[Input, Output]( - name: String, - testCases: Seq[Input] - )( - evaluator: Input => Future[Output] - )( - scorer: (Input, Output) => Double - )(implicit ec: ExecutionContext): Future[Unit] = { - - val config = EvaluationConfig.builder() - .name(name) - .build() - - val javaEval = JavaEvaluation.create[Input, Output]( - config, - testCases.asJava, - input => evaluator(input).asJava.toCompletableFuture, - (input, output) => scorer(input, output) - ) - - Future { - javaEval.run() - } - } - - /** - * Simple synchronous evaluation. - */ - def run[Input, Output]( - name: String, - testCases: Seq[Input] - )( - evaluator: Input => Output - )( - scorer: (Input, Output) => Double - ): Unit = { - - val config = EvaluationConfig.builder() - .name(name) - .build() - - JavaEvaluation.create[Input, Output]( - config, - testCases.asJava, - evaluator(_), - (input, output) => scorer(input, output) - ).run() - } -} \ No newline at end of file diff --git a/braintrust-scala/src/main/scala/dev/braintrust/scala/Logger.scala b/braintrust-scala/src/main/scala/dev/braintrust/scala/Logger.scala deleted file mode 100644 index 92b2a31..0000000 --- a/braintrust-scala/src/main/scala/dev/braintrust/scala/Logger.scala +++ /dev/null @@ -1,30 +0,0 @@ -package dev.braintrust.scala - -import dev.braintrust.log.{BraintrustLogger => JavaLogger} - -/** - * Scala-friendly logging API. - */ -object BraintrustLogger { - - def info(message: String, args: Any*): Unit = - JavaLogger.info(message, args.map(_.asInstanceOf[Object]): _*) - - def debug(message: String, args: Any*): Unit = - JavaLogger.debug(message, args.map(_.asInstanceOf[Object]): _*) - - def warn(message: String, args: Any*): Unit = - JavaLogger.warn(message, args.map(_.asInstanceOf[Object]): _*) - - def error(message: String, args: Any*): Unit = - JavaLogger.error(message, args.map(_.asInstanceOf[Object]): _*) - - def error(message: String, throwable: Throwable, args: Any*): Unit = - JavaLogger.error(message, throwable, args.map(_.asInstanceOf[Object]): _*) - - def setDebugEnabled(enabled: Boolean): Unit = - JavaLogger.setDebugEnabled(enabled) - - def isDebugEnabled: Boolean = - JavaLogger.isDebugEnabled -} \ No newline at end of file