diff --git a/.github/workflows/publish-development-version.yml b/.github/workflows/publish-development-version.yml
index d373c3827..36fa1407a 100644
--- a/.github/workflows/publish-development-version.yml
+++ b/.github/workflows/publish-development-version.yml
@@ -34,7 +34,7 @@ jobs:
- name: Assemble
uses: gradle/gradle-build-action@v2
with:
- arguments: assemble -x:xef-java-examples:assemble -x:xef-scala:assemble -x:xef-scala-examples:assemble
+ arguments: assemble
- name: Upload reports
if: failure()
@@ -46,36 +46,4 @@ jobs:
- name: Publish development version
uses: gradle/gradle-build-action@v2
with:
- arguments: publishToSonatype -x:xef-scala:publishToSonatype closeAndReleaseSonatypeStagingRepository
-
- publish-modules-with-loom:
- timeout-minutes: 30
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
- ref: ${{ github.ref_name }}
-
- - name: Set up Java
- uses: actions/setup-java@v3
- with:
- distribution: 'zulu'
- java-version: 20
-
- - name: assemble
- uses: gradle/gradle-build-action@v2
- with:
- arguments: :xef-scala:assemble :xef-java-examples:assemble
-
- - name: Upload reports
- if: failure()
- uses: actions/upload-artifact@v3
- with:
- name: 'reports-${{ matrix.os }}'
- path: '**/build/reports/**'
-
- - name: Publish development version
- uses: gradle/gradle-build-action@v2
- with:
- arguments: :xef-scala:publishToSonatype closeAndReleaseSonatypeStagingRepository
+ arguments: publishToSonatype closeAndReleaseSonatypeStagingRepository
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index f6523d87c..10b5e15a4 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -32,7 +32,7 @@ jobs:
- name: Assemble
uses: gradle/gradle-build-action@v2
with:
- arguments: assemble -x:xef-java-examples:assemble -x:xef-scala:assemble -x:xef-scala-examples:assemble
+ arguments: assemble
- name: Upload reports
if: failure()
@@ -44,36 +44,4 @@ jobs:
- name: Publish final version
uses: gradle/gradle-build-action@v2
with:
- arguments: publishToSonatype -x:xef-scala:publishToSonatype closeSonatypeStagingRepository
-
- publish-modules-with-loom:
- timeout-minutes: 30
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
- ref: ${{ github.ref_name }}
-
- - name: Set up Java
- uses: actions/setup-java@v3
- with:
- distribution: 'zulu'
- java-version: 20
-
- - name: assemble
- uses: gradle/gradle-build-action@v2
- with:
- arguments: :xef-scala:assemble :xef-java-examples:assemble
-
- - name: Upload reports
- if: failure()
- uses: actions/upload-artifact@v3
- with:
- name: 'reports-${{ matrix.os }}'
- path: '**/build/reports/**'
-
- - name: Publish final version
- uses: gradle/gradle-build-action@v2
- with:
- arguments: :xef-scala:publishToSonatype closeSonatypeStagingRepository
+ arguments: publishToSonatype closeSonatypeStagingRepository
diff --git a/README.md b/README.md
index dccf15acd..b03c15fb2 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Our goal is to make the move to this new world as simple as possible for the dev
xef.ai is packaged in two layers:
1. Core libraries bringing integration with the basic services in an AI application.
These libraries expose an _idiomatic_ interface, so there's one per programming language.
- At this moment we support Kotlin and Scala.
+ At this moment we support Kotlin.
2. Integrations with other libraries which complement the core mission of xef.ai.
xef.ai draws inspiration from libraries like [LangChain](https://docs.langchain.com/docs/)
@@ -47,10 +47,9 @@ strategies.
Libraries are published in Maven Central, under the `com.xebia` group.
-1. `xef-kotlin` for Kotlin support, `xef-scala` for Scala, `xef-java` for Java.
+1. `xef-kotlin` for Kotlin support.
2. The name of a library we provide integration for, like `xef-lucene`.
-
Gradle (Kotlin DSL)
Libraries are published in Maven Central. You may need to add that repository explicitly
@@ -73,51 +72,14 @@ We publish all libraries at once under the same version, so
[version catalogs](https://docs.gradle.org/current/userguide/platforms.html#sec:sharing-catalogs)
could be useful.
-
-
-
- SBT
-
-```sbt
-libraryDependencies += "com.xebia" %% "xef-scala" % ""
-```
-
-> **Warning**
-> `xef-scala` is currently only available for Scala 3, and depends on project [Loom](https://openjdk.org/projects/loom/),
-> so you will need at least Java 20 to use the library.
-
-
-
-
- Maven
-
-Libraries are published in Maven Central. You may need to add that repository explicitly
-in your build, if you haven't done it before.
-
-```xml
-
- com.xebia
- xef-java
- x.x.x
- pom
- runtime
-
-```
-
-
-
## 📖 Quick Introduction
In this small introduction we look at the main features of xef, including the `conversation` function.
-- [ Kotlin version](https://github.com/xebia-functional/xef/blob/main/docs/intro/kotlin.md)
-- [ Scala version](https://github.com/xebia-functional/xef/blob/main/docs/intro/scala.md)
-- [ Java version](https://github.com/xebia-functional/xef/blob/main/docs/intro/java.md)
+- [ Quick introduction to xef.ai](https://github.com/xebia-functional/xef/blob/main/docs/intro/kotlin.md)
## 🚀 Examples
You can also have a look at the examples to have a feeling of how using the library looks like.
- [ Examples in Kotlin](https://github.com/xebia-functional/xef/tree/main/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation)
-- [ Examples in Scala](https://github.com/xebia-functional/xef/tree/main/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala)
-- [ Examples in Java](https://github.com/xebia-functional/xef/tree/main/examples/java/src/main/java/com/xebia/functional/xef/java/auto)
diff --git a/buildSrc/src/main/kotlin/ScalaPublishingConventionsPlugin.kt b/buildSrc/src/main/kotlin/ScalaPublishingConventionsPlugin.kt
deleted file mode 100644
index 400817204..000000000
--- a/buildSrc/src/main/kotlin/ScalaPublishingConventionsPlugin.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.plugins.BasePlugin
-import org.gradle.api.plugins.BasePluginExtension
-import org.gradle.api.publish.PublishingExtension
-import org.gradle.api.publish.maven.MavenPublication
-import org.gradle.api.tasks.TaskProvider
-import org.gradle.api.tasks.bundling.Jar
-import org.gradle.kotlin.dsl.findByType
-import org.gradle.kotlin.dsl.get
-import org.gradle.kotlin.dsl.register
-import org.gradle.plugins.signing.SigningExtension
-
-class ScalaPublishingConventionsPlugin : Plugin {
-
- override fun apply(project: Project): Unit = project.run {
- val scaladocJarTask: TaskProvider = tasks.register("scaladocJar") {
- group = BasePlugin.BUILD_GROUP
- tasks.findByName("scaladoc")?.let { dependsOn(it) }
- ?: errorMessage("The scaladoc task was not found. The Javadoc jar file won't contain any documentation")
- archiveClassifier.set("javadoc")
- from("${layout.buildDirectory.get()}/docs/scaladoc")
- }
-
- val publishingExtension: PublishingExtension =
- extensions.findByType()
- ?: throw IllegalStateException("The Maven Publish plugin is required to publish the build artifacts")
-
- val signingExtension: SigningExtension =
- extensions.findByType()
- ?: throw IllegalStateException("The Signing plugin is required to digitally sign the built artifacts")
-
- val basePluginExtension: BasePluginExtension =
- extensions.findByType()
- ?: throw IllegalStateException("The Base plugin is required to configure the name of artifacts")
-
- publishingExtension.run {
- publications {
- register("maven") {
- val scala3Suffix = "_3"
- artifactId = basePluginExtension.archivesName.get() + scala3Suffix
- from(components["java"])
- artifact(scaladocJarTask)
- pomConfiguration(project)
- }
- }
- }
-
- signingExtension.run {
- val isLocal = gradle.startParameter.taskNames.any { it.contains("publishToMavenLocal", ignoreCase = true) }
- val signingKeyId: String? = configValue("signing.keyId", "SIGNING_KEY_ID")
- val signingKey: String? = configValue("signing.key", "SIGNING_KEY")
- val signingPassphrase: String? = configValue("signing.passphrase", "SIGNING_KEY_PASSPHRASE")
- isRequired = !isLocal
- useGpgCmd()
- useInMemoryPgpKeys(signingKeyId, signingKey, signingPassphrase)
- sign(publishingExtension.publications)
- }
- }
-}
diff --git a/buildSrc/src/main/kotlin/xef-scala-publishing-conventions.gradle.kts b/buildSrc/src/main/kotlin/xef-scala-publishing-conventions.gradle.kts
deleted file mode 100644
index 97fa1cfd8..000000000
--- a/buildSrc/src/main/kotlin/xef-scala-publishing-conventions.gradle.kts
+++ /dev/null
@@ -1 +0,0 @@
-apply()
diff --git a/core/TECHNICAL.MD b/core/TECHNICAL.MD
index 22b88ceb0..70969ee8e 100644
--- a/core/TECHNICAL.MD
+++ b/core/TECHNICAL.MD
@@ -14,11 +14,9 @@ The breakdown is only in terms of JVM, since that's where we _mostly_ care about
We include the following dependencies in our _core_ module to implement a _common_ layer to interact with LLMs.
The dependency on Kotlin Stdlib is unavoidable, since we use Kotlin as our main language.
-We also require KotlinX Coroutines such that we can leverage the `suspend` keyword in our API and expose `Future` to the
-Java/Scala API.
-Additionally, we also have a need for a HTTP client, and a serialization framework. Here we use Ktor and KotlinX
-Serialization respectively,
-and Xef relies on the CIO engine for Ktor, which avoids any additional dependencies.
+We also require KotlinX Coroutines such that we can leverage the `suspend` keyword in our API.
+Additionally, we also have a need for an HTTP client, and a serialization framework. Here we use Ktor and KotlinX
+Serialization respectively, and Xef relies on the CIO engine for Ktor, which avoids any additional dependencies.
- kotlin-stdlib (1810 Kb = 1598 Kb + 212 Kb)
- kotlinx-coroutines-core (1608 Kb = 1442 Kb + 166 Kb)
diff --git a/docs/intro/java.md b/docs/intro/java.md
deleted file mode 100644
index 2d16ccdc7..000000000
--- a/docs/intro/java.md
+++ /dev/null
@@ -1,193 +0,0 @@
-# Quick introduction to xef.ai (Java version)
-
-After adding the library to your project
-(see the [main README](https://github.com/xebia-functional/xef/blob/main/README.md) for instructions),
-you get access to the `AIScope` class, which is your port of entry to the modern AI world.
-Using it, you can _prompt_ for information, which means posing the question to an LLM
-(Large Language Model). The easiest way is to just get the information back as a string.
-
-```java
-package my.example;
-
-import com.xebia.functional.xef.java.auto.AIScope;
-
-import java.util.concurrent.ExecutionException;
-
-public class Example {
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (AIScope scope = new AIScope()) {
- String topic = "artificial intelligence";
- scope.promptMessage("Give me a selection of books about " + topic)
- .thenAccept(System.out::println)
- .get();
- }
- }
-}
-```
-
-> **Note**
-> By default the `AIScope` connects to [OpenAI](https://platform.openai.com/).
-> To use their services you should provide the corresponding API key in the `OPENAI_TOKEN`
-> environment variable, and have enough credits.
-
-In the example above we create an `AIScope` using the `try-with-resources` syntax,
-which ensures that the scope is closed at the end of the block.
-The `AIScope` gives us access to the `promptMessage` & co functions, which allow us to interact with the LLM.
-
-All the functions of `AIScope` are returned as a `Future` for maximum backward compatibility until JDK8,
-but you can inject `Executors.newVirtualThreadPerTaskExecutor()` to have the `Future`s work on virtual threads.
-
-Remember that exceptions in `Future`are wrapped in `ExecutionException`,
-so to inspect the actual exception you need to call `getCause()` on it.
-_Structured Concurrency_ is implemented under the hood by Kotlin's `CoroutineScope`,
-and all futures are cancelled when the `AIScope` is closed and `Future#get` will throw `CancellationException`.
-
-In the next examples we'll write functions that rely on `AIScope`'s DSL functionality
-
-## Structure
-
-
-The output from the `books` function above may be hard to parse back from the
-strings we obtain. Fortunately, you can also ask xef.ai to give you back the information
-using a _custom type_. The library takes care of instructing the LLM on building such
-a structure, and deserialize the result back for you.
-
-We can thus define a `Book` class that describes the desired response we want to receive from the LLM.
-Relying on [Jakarta validation](https://beanvalidation.org) we can also specify which fields are mandatory using `NotNull`,
-or include additional constraints in the [Json Schema](https://json-schema.org).
-
-xef.ai reuses [Jackson](https://github.com/FasterXML/jackson-databind),
-and [JsonSchema generator](https://github.com/victools/jsonschema-generator) to parse and generate the Json Schema V7 for you.
-
-```java
-package my.example;
-
-import jakarta.validation.constraints.NotNull;
-
-public class Book {
- @NotNull public String title;
- @NotNull public String author;
- @NotNull public int year;
- @NotNull public String genre;
-
- @Override
- public String toString() {
- return "Book{" +
- "title='" + title + '\'' +
- ", author='" + author + '\'' +
- ", year=" + year +
- ", genre='" + genre + '\'' +
- '}';
- }
-}
-```
-
-Using the definition of `Book`, we can rewrite our previous example as:
-
-```java
-package my.example;
-
-import com.xebia.functional.xef.java.auto.AIScope;
-import jakarta.validation.constraints.NotNull;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-public class Example {
-
- private final AIScope scope;
-
- public Example(AIScope scope) {
- this.scope = scope;
- }
-
- public CompletableFuture bookSelection(String topic) {
- return scope.prompt("Give me a selection of books about " + topic, Example.Book.class);
- }
-
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (AIScope scope = new AIScope()) {
- Example example = new Example(scope);
- example.bookSelection("artificial intelligence")
- .thenAccept(System.out::println)
- .get();
- }
- }
-}
-```
-
-Here we also show how you can easily capture the `AIScope` in a class,
-and build and compose additional functionality on top.
-If you're using any dependency injection framework, you can also construct `AIScope` and inject it as usual.
-Make sure that the dependency injection framework properly closes the `AIScope` when the application shuts down.
-
-## Context
-
-LLMs have knowledge about a broad variety of topics. But by construction they are not able
-to respond to questions about information not available in their training set. However, you
-often want to supplement the LLM with more data:
-- Transient information referring to the current moment, like the current weather, or
- the trends in the stock market in the past 10 days.
-- Non-public information, for example for summarizing a piece of text you're creating
- within you organization.
-
-These additional pieces of information are called the _contextScope_ in xef.ai, and are attached
-to every question to the LLM. Although you can add arbitrary strings to the context at any
-point, the most common mode of usage is using an _agent_ to consult an external service,
-and make its response part of the context. One such agent is `search`, which uses a web
-search service to enrich that context.
-
-```java
-package my.example;
-
-import java.util.concurrent.CompletableFuture;
-
-public class Weather {
- private final AIScope scope;
-
- public Weather(AIScope scope) {
- this.scope = scope;
- }
-
- public CompletableFuture recommendation() {
- return scope.contextScope(scope.search("Weather in $place"), () ->
- scope.promptMessage("Knowing this forecast, what clothes do you recommend I should wear?")
- );
- }
-}
-```
-
-> **Note**
-> The underlying mechanism of the context is a _vector store_, a data structure which
-> saves a set of strings, and is able to find those similar to another given one.
-> By default xef.ai uses an _in-memory_ vector store, since it provides maximum
-> compatibility across platforms. However, if you foresee your context growing above
-> the hundreds of elements, you may consider switching to another alternative, like
-> Lucene or PostgreSQL.
->
-> ```java
-> package my.example;
->
-> import com.xebia.functional.xef.store.LuceneKt;
->
-> import java.nio.file.Path;
-> import java.util.concurrent.CompletableFuture;
->
-> public class VectorStore {
->
-> private final AIScope scope;
->
-> public VectorStore(AIScope scope) {
-> this.scope = scope;
-> }
->
-> public void example() {
-> Path LUCENE_PATH = Path.of("lucene");
-> scope.contextScope(
-> LuceneKt.InMemoryLuceneBuilder(LUCENE_PATH),
-> () -> CompletableFuture.completedFuture("do stuff")
-> );
-> }
->
-> }
-> ```
diff --git a/docs/intro/scala.md b/docs/intro/scala.md
deleted file mode 100644
index 3ecb49a23..000000000
--- a/docs/intro/scala.md
+++ /dev/null
@@ -1,146 +0,0 @@
-# Quick introduction to xef.ai (Scala version)
-
-After adding the library to your project (see the
-[main README](https://github.com/xebia-functional/xef/blob/main/README.md) for instructions),
-you get access to the `conversation` function, which is your port of entry to the modern AI world.
-Inside of it, you can _prompt_ for information, which means posing the question to an LLM
-(Large Language Model). The easiest way is to just get the information back as a string or list of strings.
-
-```scala 3
-import com.xebia.functional.xef.scala.conversation.*
-
-def books(topic: String): Unit = conversation:
- val topBook: String = promptMessage(s"Give me the top-selling book about $topic")
- println(topBook)
- val selectedBooks: List[String] = promptMessages(s"Give me a selection of books about $topic")
- println(selectedBooks.mkString("\n"))
-```
-
-## Additional setup
-
-If the code above fails, you may need to perform some additional setup.
-
-### OpenAI
-
-By default, the `conversation` block connects to [OpenAI](https://platform.openai.com/).
-To use their services you should provide the corresponding API key in the `OPENAI_TOKEN`
-environment variable, and have enough credits.
-
-
-SBT
-
-```shell
-env OPENAI_TOKEN= sbt
-```
-
-
-
-IntelliJ
-
-Set the environment variable `OPENAI_TOKEN=xxx`
-
-
-
-### Project Loom
-
-The Scala module depends on project [Loom](https://openjdk.org/projects/loom/),
-so you will need at least Java 20 to use the library. Furthermore, if using Java 20 specifically,
-you need to pass the `--enable-preview` flag.
-
-
-SBT
-
-```shell
-env OPENAI_TOKEN= sbt -J--enable-preview
-```
-
-
-
-IntelliJ
-
-- Set the Java version to at least 20
-- If using Java 20 specifically, set VM options to `--enable-preview`
-
-
-
-## Structure
-
-The output from the `books` function above may be hard to parse back from the
-strings we obtain. Fortunately, you can also ask xef.ai to give you back the information
-using a _custom type_. The library takes care of instructing the LLM on building such
-a structure, and deserialize the result back for you.
-
-This can be done by declaring a case class that `derives SerialDescriptor, Decoder`:
-
-```scala 3
-import com.xebia.functional.xef.scala.conversation.*
-import com.xebia.functional.xef.scala.serialization.*
-import io.circe.Decoder
-
-case class Book(name: String, author: String, pages: Int) derives SerialDescriptor, Decoder
-```
-
-The `conversation` block can then be written in this way:
-
-```scala 3
-def bookExample(topic: String): Unit = conversation:
- val Book(title, author, pages) = prompt[Book](s"Give me the best-selling book about $topic")
- println(s"The book $title is by $author and has $pages pages.")
-```
-
-xef.ai for Scala uses xef.ai core, which is based on the Kotlin implementation. Hence, the core
-reuses [Kotlin's common serialization](https://kotlinlang.org/docs/serialization.html), and
-Scala uses [circe](https://github.com/circe/circe) to derive the required serializable instance.
-The LLM is usually able to detect which kind of information should go in each field based on its name
-(like `title` and `author` above).
-
-## Context
-
-LLMs have knowledge about a broad variety of topics. But by construction they are not able
-to respond to questions about information not available in their training set. However, you
-often want to supplement the LLM with more data:
-- Transient information referring to the current moment, like the current weather, or
- the trends in the stock market in the past 10 days.
-- Non-public information, for example for summarizing a piece of text you're creating
- within your organization.
-
-These additional pieces of information are called the _context_ in xef.ai, and are attached
-to every question to the LLM. Although you can add arbitrary strings to the context at any
-point, the most common mode of usage is using an _agent_ to consult an external service,
-and make its response part of the context. One such agent is `search`, which uses the
-[Google Search API (SerpApi)](https://serpapi.com/) to enrich that context.
-
-(Note that a SerpApi token may be required to run this example.)
-
-```scala 3
-import com.xebia.functional.xef.conversation.llm.openai.*
-import com.xebia.functional.xef.reasoning.serpapi.*
-import com.xebia.functional.xef.scala.conversation.*
-import com.xebia.functional.xef.scala.serialization.*
-import io.circe.Decoder
-
-val openAI: OpenAI = OpenAI.FromEnvironment
-
-def setContext(query: String)(using conversation: ScalaConversation): Unit =
- addContext(Search(openAI.DEFAULT_CHAT, conversation, 3).search(query).get)
-
-@main def runWeather(): Unit = conversation:
- setContext("Weather in Cádiz, Spain")
- val question = "Knowing this forecast, what clothes do you recommend I should wear if I live in Cádiz?"
- val answer = promptMessage(question)
- println(answer)
-```
-
-> **Note**
-> The underlying mechanism of the context is a _vector store_, a data structure which
-> saves a set of strings, and is able to find those similar to another given one.
-> By default xef.ai uses an _in-memory_ vector store, since this provides maximum
-> compatibility across platforms. However, if you foresee your context growing above
-> the hundreds of elements, you may consider switching to another alternative, like
-> Lucene or PostgreSQL.
-
-## Examples
-
-Check out the
-[examples folder](https://github.com/xebia-functional/xef/blob/main/examples/scala/src/main/scala/com/xebia/functional/xef/examples)
-for a complete list of different use cases.
diff --git a/examples/java/build.gradle.kts b/examples/java/build.gradle.kts
deleted file mode 100644
index aded6cd45..000000000
--- a/examples/java/build.gradle.kts
+++ /dev/null
@@ -1,16 +0,0 @@
-@file:Suppress("DSL_SCOPE_VIOLATION")
-
-plugins {
- java
- alias(libs.plugins.spotless)
-}
-
-dependencies {
- implementation(projects.xefJava)
- implementation(projects.xefReasoning)
- implementation(projects.xefGpt4all)
-}
-
-tasks.test {
- useJUnitPlatform()
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/BreakingNews.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/BreakingNews.java
deleted file mode 100644
index 71585a02c..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/BreakingNews.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.contexts;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-import com.xebia.functional.xef.reasoning.serpapi.Search;
-
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-public class BreakingNews {
-
- static DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/M/yyyy");
- static LocalDateTime now = LocalDateTime.now();
-
- public record BreakingNew(String summary) {
- }
-
- private static CompletableFuture writeParagraph(PlatformConversation scope) {
- var currentDate = dtf.format(now);
-
- return scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt("write a paragraph of about 300 words about: " + currentDate + " Covid News"), BreakingNews.BreakingNew.class)
- .thenAccept(breakingNews -> System.out.println(currentDate + " Covid news summary:\n" + breakingNews));
- }
-
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (PlatformConversation scope = OpenAI.conversation()) {
- var currentDate = dtf.format(now);
- var search = new Search(OpenAI.FromEnvironment.DEFAULT_CHAT, scope, 3);
- scope.addContextFromArray(search.search(currentDate + " Covid News").get());
- writeParagraph(scope).get();
- }
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/DivergentTasks.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/DivergentTasks.java
deleted file mode 100644
index 6ed37bfac..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/DivergentTasks.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.contexts;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-import com.xebia.functional.xef.reasoning.serpapi.Search;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-public class DivergentTasks {
-
- public Long numberOfMedicalNeedlesInWorld;
-
- private static CompletableFuture numberOfMedical(PlatformConversation scope) {
- return scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt("Provide the number of medical needles in the world"), DivergentTasks.class)
- .thenAccept(numberOfNeedles -> System.out.println("Needles in world:\n" + numberOfNeedles.numberOfMedicalNeedlesInWorld));
- }
-
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (PlatformConversation scope = OpenAI.conversation()) {
- Search search = new Search(OpenAI.FromEnvironment.DEFAULT_CHAT, scope, 3);
- scope.addContextFromArray(search.search("Estimate amount of medical needles in the world").get());
- numberOfMedical(scope).get();
- }
- }
-
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/Markets.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/Markets.java
deleted file mode 100644
index 4cef77efa..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/Markets.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.contexts;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-import com.xebia.functional.xef.reasoning.serpapi.Search;
-
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-public class Markets {
-
- public record Market(String news, List raisingStockSymbols, List decreasingStockSymbols) {
- }
-
- private static CompletableFuture stockMarketSummary(PlatformConversation scope) {
- var news = new Prompt("Write a short summary of the stock market results given the provided context.");
-
- return scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, news, Market.class)
- .thenAccept(markets -> System.out.println(markets));
- }
-
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (PlatformConversation scope = OpenAI.conversation()) {
- var dtf = DateTimeFormatter.ofPattern("dd/M/yyyy");
- var now = LocalDateTime.now();
- var currentDate = dtf.format(now);
- var search = new Search(OpenAI.FromEnvironment.DEFAULT_CHAT, scope, 3);
- scope.addContextFromArray(search.search(currentDate + "Stock market results, raising stocks, decreasing stocks").get());
- stockMarketSummary(scope).get();
- }
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/PDFDocument.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/PDFDocument.java
deleted file mode 100644
index e57b69aa6..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/PDFDocument.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.contexts;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.java.auto.jdk21.util.ConsoleUtil;
-import com.xebia.functional.xef.prompt.Prompt;
-import com.xebia.functional.xef.reasoning.pdf.PDF;
-
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-
-public class PDFDocument {
-
- private static ConsoleUtil util = new ConsoleUtil();
-
- public record AIResponse(String answer, String source){}
-
- private static final String PDF_URL = "https://people.cs.ksu.edu/~schmidt/705a/Scala/Programming-in-Scala.pdf";
-
- private static CompletableFuture askQuestion(PlatformConversation scope) {
- System.out.println("Enter your question ( to exit): ");
-
-
- var line = util.readLine();
- if (line == null || line.isBlank()) {
- return CompletableFuture.completedFuture(null);
- } else {
- scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt(line), AIResponse.class)
- .thenAccept(aiRes -> System.out.println(aiRes.answer + "\n---\n" +
- aiRes.source + "\n---\n"));
-
- return askQuestion(scope);
- }
- }
-
- public static void main(String[] args) throws Exception {
- try (PlatformConversation scope = OpenAI.conversation()) {
- PDF pdf = new PDF(OpenAI.FromEnvironment.DEFAULT_CHAT,
- OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, scope);
- scope.addContext(List.of(pdf.readPDFFromUrl.readPDFFromUrl(PDF_URL).get()));
- askQuestion(scope).get();
- }
- finally {
- util.close();
- }
- }
-
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/Weather.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/Weather.java
deleted file mode 100644
index 17b66c96a..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/Weather.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.contexts;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-import com.xebia.functional.xef.reasoning.serpapi.Search;
-
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-public class Weather {
- public List answer;
-
- private static CompletableFuture clothesRecommend(PlatformConversation scope) {
- return scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt("Knowing this forecast, what clothes do you recommend I should wear?"), Weather.class)
- .thenAccept(weather ->
- System.out.println(weather.answer)
- );
- }
-
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (PlatformConversation scope = OpenAI.conversation()) {
- Search search = new Search(OpenAI.FromEnvironment.DEFAULT_CHAT, scope, 3);
- scope.addContextFromArray(search.search("Weather in Cádiz, Spain").get());
- clothesRecommend(scope).get();
- }
- }
-
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/conversations/Animals.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/conversations/Animals.java
deleted file mode 100644
index 9ff1524c3..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/conversations/Animals.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.conversations;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.JvmPromptBuilder;
-import com.xebia.functional.xef.prompt.Prompt;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-public class Animals {
-
- private final PlatformConversation scope;
-
- public Animals(PlatformConversation scope) {
- this.scope = scope;
- }
-
- public CompletableFuture uniqueAnimal() {
- return scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt("A unique animal species."), Animal.class);
- }
-
- public CompletableFuture groundbreakingInvention() {
- return scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt("A groundbreaking invention from the 20th century."), Invention.class);
- }
-
- public CompletableFuture story(Animal animal, Invention invention) {
- Prompt storyPrompt = new JvmPromptBuilder()
- .addSystemMessage("You are a writer for a science fiction magazine.")
- .addUserMessage("Write a short story of 200 words that involves the animal and the invention")
- .build();
- return scope.promptMessage(OpenAI.FromEnvironment.DEFAULT_CHAT, storyPrompt);
- }
-
- public record Animal(String name, String habitat, String diet){}
- public record Invention(String name, String inventor, int year, String purpose){}
-
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (PlatformConversation scope = OpenAI.conversation()) {
- Animals animals = new Animals(scope);
- animals.uniqueAnimal()
- .thenCompose(animal ->
- animals.groundbreakingInvention()
- .thenCompose(invention ->
- animals.story(animal, invention)
- .thenAccept(System.out::println)
- )).get();
- }
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/gpt4all/Chat.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/gpt4all/Chat.java
deleted file mode 100644
index 6c16baded..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/gpt4all/Chat.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.gpt4all;
-
-import com.xebia.functional.gpt4all.GPT4All;
-import com.xebia.functional.gpt4all.Gpt4AllModel;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-import org.reactivestreams.Subscriber;
-import org.reactivestreams.Subscription;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.file.Path;
-import java.util.Objects;
-import java.util.concurrent.ExecutionException;
-
-public class Chat {
- public static void main(String[] args) throws ExecutionException, InterruptedException, IOException {
- var userDir = System.getProperty("user.dir");
- var path = userDir + "/models/gpt4all/ggml-replit-code-v1-3b.bin";
-
- var supportedModels = Gpt4AllModel.Companion.getSupportedModels();
-
- supportedModels.forEach(it -> {
- var url = (Objects.nonNull(it.getUrl())) ? " - " + it.getUrl() : "";
- System.out.println("🤖 " + it.getName() + url);
- });
-
- var url = "https://huggingface.co/nomic-ai/ggml-replit-code-v1-3b/resolve/main/ggml-replit-code-v1-3b.bin";
- var modelPath = Path.of(path);
- var gpt4all = GPT4All.Companion.invoke(url, modelPath);
-
- System.out.println("🤖 GPT4All loaded: " + gpt4all);
- /**
- * Uses internally [HuggingFaceLocalEmbeddings] default of "sentence-transformers", "msmarco-distilbert-dot-v5"
- * to provide embeddings for docs in contextScope.
- */
-
- try (var scope = OpenAI.conversation();
- var br = new BufferedReader(new InputStreamReader(System.in))) {
-
- System.out.println("\n🤖 Enter your question: ");
-
- while(true){
- String line = br.readLine();
- if (line.equals("exit")) break;
-
- var answer = scope.promptStreamingToPublisher(gpt4all, new Prompt(line));
-
- answer.subscribe(new Subscriber() {
- StringBuilder answer = new StringBuilder();
-
- @Override
- public void onSubscribe(Subscription s) {
- System.out.print("\n🤖 --> " + s);
- s.request(Long.MAX_VALUE);
- }
-
- @Override
- public void onNext(String s) {
- answer.append(s);
- }
-
- @Override
- public void onError(Throwable t) {
- System.out.println(t);
- }
-
- @Override
- public void onComplete() {
- System.out.println("\n🤖 --> " + answer.toString());
- System.out.println("\n🤖 --> Done");
- System.out.println("\n🤖 Enter your question: ");
- }
- });
- }
- }
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/ASCIIArt.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/ASCIIArt.java
deleted file mode 100644
index e04fd177e..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/ASCIIArt.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.serialization;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-
-import java.util.concurrent.ExecutionException;
-
-public class ASCIIArt {
- public String art;
-
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (PlatformConversation scope = OpenAI.conversation()) {
- scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt("ASCII art of a cat dancing"), ASCIIArt.class)
- .thenAccept(art -> System.out.println(art.art))
- .get();
- }
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Book.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Book.java
deleted file mode 100644
index 3f090bec9..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Book.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.serialization;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-
-import java.util.concurrent.ExecutionException;
-
-public class Book {
-
- public String title;
- public String author;
- public String summary;
-
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (PlatformConversation scope = OpenAI.conversation()) {
- scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt("To Kill a Mockingbird by Harper Lee summary."), Book.class)
- .thenAccept(book -> System.out.println("To Kill a Mockingbird summary:\n" + book.summary))
- .get();
- }
- }
-
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Books.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Books.java
deleted file mode 100644
index 75f6487da..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Books.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.serialization;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-import jakarta.validation.constraints.NotNull;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-public class Books {
-
- private final PlatformConversation scope;
-
- public Books(PlatformConversation scope) {
- this.scope = scope;
- }
-
- public record Book(@NotNull String title, @NotNull String author, @NotNull int year, @NotNull String genre){}
-
- public CompletableFuture bookSelection(String topic) {
- return scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt("Give me a selection of books about " + topic), Books.Book.class);
- }
-
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (PlatformConversation scope = OpenAI.conversation()) {
- Books books = new Books(scope);
- books.bookSelection("artificial intelligence")
- .thenAccept(System.out::println)
- .get();
- }
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/ChessAI.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/ChessAI.java
deleted file mode 100644
index bb50947d5..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/ChessAI.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.serialization;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-
-import java.util.ArrayList;
-import java.util.concurrent.ExecutionException;
-import java.util.stream.Collectors;
-
-public class ChessAI {
-
- public record ChessMove(String player, String move){}
- public record ChessBoard(String board){}
- public record GameState(Boolean ended, String winner){}
-
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (PlatformConversation scope = OpenAI.conversation()) {
- var moves = new ArrayList();
- var gameEnded = false;
- var winner = "";
-
- while (!gameEnded) {
- var currentPlayer = ((moves.size() % 2) == 0) ? "Player 1 (White)" : "Player 2 (Black)";
-
- var prompt = String.format("""
- |%s, it's your turn.
- |Previous moves: %s
- |Make your next move:""",
- currentPlayer,
- moves.stream().map(ChessMove::toString).collect(Collectors.joining(", ")));
-
- ChessMove move = scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt(prompt), ChessMove.class).get();
- moves.add(move);
-
- // Update boardState according to move.move
- // ...
-
- var boardPrompt = String.format("""
- Given the following chess moves: %s,
- generate a chess board on a table with appropriate emoji representations for each move and piece.
- Add a brief description of the move and it's implications""",
- moves.stream().map(it -> it.player + ":" + it.move).collect(Collectors.joining(", ")));
-
- ChessBoard chessBoard= scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt(boardPrompt), ChessBoard.class).get();
- System.out.println("Current board:\n" + chessBoard.board);
-
- var gameStatePrompt = String.format("""
- Given the following chess moves: %s,
- has the game ended (win, draw, or stalemate)?""",
- moves.stream().map(ChessMove::toString).collect(Collectors.joining(", ")));
-
- GameState gameState = scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt(gameStatePrompt), GameState.class).get();
-
- gameEnded = gameState.ended;
- winner = gameState.winner;
- }
-
- System.out.println("Game over. Final move: " + moves.get(moves.size() - 1) + ", Winner: " + winner);
- }
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Movies.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Movies.java
deleted file mode 100644
index 2ae736fd8..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Movies.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.serialization;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-
-import java.util.concurrent.ExecutionException;
-
-public class Movies {
-
- public record Movie(String title, String genre, String director){}
-
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (PlatformConversation scope = OpenAI.conversation()) {
- scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt("Please provide a movie title, genre and director for the Inception movie"), Movie.class)
- .thenAccept(movie -> System.out.println(movie))
- .get();
- }
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Recipes.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Recipes.java
deleted file mode 100644
index 1439c72af..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Recipes.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.serialization;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-
-public class Recipes {
-
- public record Recipe(String name, List ingredients){}
-
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- try (PlatformConversation scope = OpenAI.conversation()) {
- var recipe = scope.prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, new Prompt("Recipe for chocolate chip cookies."), Recipe.class).get();
- System.out.println("The recipe for " + recipe.name + " is " + recipe.ingredients );
- }
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Checker.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Checker.java
deleted file mode 100644
index 59a53b3a8..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Checker.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.tot;
-
-public class Checker {
-
- public static Solutions.Solution checkSolution(Solutions.Solution response){
- System.out.println("✅ Validating solution: " + Rendering.truncateText(response.answer) + "...");
- return response.isValid ? response :
- Solutions.makeSolution(response.answer, false, "Invalid solution", null);
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/ControlSignals.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/ControlSignals.java
deleted file mode 100644
index 82584872c..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/ControlSignals.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.tot;
-
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-
-import static com.xebia.functional.xef.java.auto.jdk21.tot.Rendering.renderHistory;
-import static com.xebia.functional.xef.java.auto.jdk21.tot.Rendering.truncateText;
-
-import java.util.concurrent.CompletableFuture;
-
-public class ControlSignals {
-
- static class ControlSignal {
- public String value = "";
- }
-
- public static CompletableFuture controlSignal(Problems.Memory memory){
- System.out.println("\uD83E\uDDE0 Generating control signal for problem:" + truncateText(memory.problem.description) + "...");
- var guidancePrompt = new Prompt(Rendering.trimMargin(
- " You are an expert advisor on information extraction.\n" +
- " You generate guidance for a problem.\n" +
- " " + renderHistory(memory) + "\n" +
- " You are given the following problem:\n" +
- " " + memory.problem.description + "\n" +
- " Instructions:\n" +
- " 1. Generate 1 guidance to get the best results for this problem.\n" +
- " 2. Ensure the guidance is relevant to the problem.\n" +
- " 3. Ensure the guidance is accurate, complete, and unambiguous.\n" +
- " 4. Ensure the guidance is actionable.\n" +
- " 5. Ensure the guidance accounts for previous answers in the `history`.\n" +
- " \n"));
-
- return Problems.Memory.getAiScope().prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, guidancePrompt, ControlSignal.class);
- }
-
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Critiques.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Critiques.java
deleted file mode 100644
index b835c0c69..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Critiques.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.tot;
-
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-
-import static com.xebia.functional.xef.java.auto.jdk21.tot.Rendering.truncateText;
-
-import java.util.concurrent.CompletableFuture;
-
-public class Critiques {
-
- static class Critique {
- public String answer;
- public String reasoning;
- public boolean answerTrulyAccomplishesTheGoal;
- }
-
- public static CompletableFuture critique(Problems.Memory memory, Solutions.Solution currentSolution){
- System.out.println("🕵️ Critiquing solution: " + truncateText(currentSolution.answer) + "...");
-
- var prompt = new Prompt(Rendering.trimMargin(
- " You are an expert advisor critiquing a solution.\n" +
- " \n" +
- " Previous history:\n" +
- " " + Rendering.renderHistory(memory) + "\n" +
- " \n" +
- " You are given the following problem:\n" +
- " " + memory.problem.description + "\n" +
- " \n" +
- " You are given the following solution:\n" +
- " " + currentSolution.answer + "\n" +
- " \n" +
- " Instructions:\n" +
- " 1. Provide a critique and determine if the answer truly accomplishes the goal.\n" +
- " \n"));
-
- return Problems.Memory.getAiScope().prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, prompt, Critique.class);
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Main.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Main.java
deleted file mode 100644
index 67cae5025..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Main.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.tot;
-
-public class Main {
-
- private static final int MAX_ROUNDS = 5;
-
- public static void main(String[] args) {
- Problems.Problem problem = new Problems.Problem();
- problem.description = Rendering.trimMargin(
- " You are an expert functional programmer.\n" +
- " 1. You never throw exceptions.\n" +
- " 2. You never use null.\n" +
- " 3. You never use `for` `while` or loops in general, prefer tail recursion.\n" +
- " 4. You never use mutable state.\n" +
- " \n" +
- " This code is unsafe. Find the problems in this code and provide a Github suggestion code fence with the `diff` to fix it.\n" +
- " \n" +
- " ```kotlin\n" +
- " fun access(list: List, index: Int): Int {\n" +
- " return list[index]\n" +
- " }\n" +
- " ```\n" +
- " \n" +
- " Return a concise solution that fixes the problems in the code.");
-
-
- var solve = Problems.solve(problem, MAX_ROUNDS);
-
- System.out.println("✅ Final solution: " + solve.answer);
- System.out.println("✅ Solution validity: " + solve.isValid);
- System.out.println("✅ Solution reasoning: " + solve.reasoning);
- System.out.println("✅ Solution code: " + solve.value);
- }
-
- static class FinalSolution {
- public String solution;
- }
-
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Problems.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Problems.java
deleted file mode 100644
index 167225f00..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Problems.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.tot;
-
-import com.xebia.functional.xef.conversation.PlatformConversation;
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Stream;
-
-import static com.xebia.functional.xef.java.auto.jdk21.tot.Rendering.truncateText;
-
-public class Problems {
-
- static class Problem{
- public String description;
- }
-
- public static Solutions.Solution solve(Problem problem, int maxRounds) {
- try(Memory initialMemory = new Memory<>(problem, new ArrayList<>())) {
- return solveRec(maxRounds, initialMemory);
- }
- }
-
- private static Solutions.Solution solveRec(int remainingRounds, Memory sMemory) {
- if(remainingRounds <= 0){
- System.out.println("❌ Maximum rounds reached. Unable to find a solution.");
- return Solutions.makeSolution("", false, "No Response", null);
- } else{
- System.out.println("🌱 Solving problem: " +
- truncateText(sMemory.problem.description, 100) +
- " (Remaining rounds: " + remainingRounds + "...");
-
- ControlSignals.ControlSignal controlSignal = getControlSignal(sMemory);
- Solutions.Solution response = Solutions.solution(sMemory, controlSignal);
- Solutions.Solution result = Checker.checkSolution(response);
- Memory updatedMemory = sMemory.addResult(result);
- if(result.isValid){
- System.out.println("✅ Solution found: " + truncateText(result.answer) + "!");
- Critiques.Critique critique = getCritique(result, updatedMemory);
- if(critique != null && critique.answerTrulyAccomplishesTheGoal){
- System.out.println("❌ Solution does not accomplish the goal: " + truncateText(result.answer) + "!");
- System.out.println("⏪ Backtracking...");
- return solveRec(remainingRounds - 1, updatedMemory);
- }
- else {
- return result;
- }
- }
- else{
- System.out.println("⏪ Backtracking...");
- return solveRec(remainingRounds - 1, updatedMemory);
- }
- }
- }
-
- private static ControlSignals.ControlSignal getControlSignal(Memory sMemory) {
- try {
- ControlSignals.ControlSignal controlSignal = ControlSignals.controlSignal(sMemory).get();
- System.out.println("\uD83E\uDDE0 Generated control signal: " + truncateText(controlSignal.value));
- return controlSignal;
- } catch (Exception e) {
- System.err.printf("ControlSignals.controlSignal prompt threw exception: %s - %s\n",
- e.getClass().getName(), e.getMessage());
- return new ControlSignals.ControlSignal();
- }
- }
-
- @Nullable
- private static Critiques.Critique getCritique(Solutions.Solution result, Memory updatedMemory) {
- try {
- return Critiques.critique(updatedMemory, result).get();
- } catch (Exception e) {
- System.err.printf("Critiques.critique prompt threw exception: %s - %s\n",
- e.getClass().getName(), e.getMessage());
- return null;
- }
- }
-
- static class Memory implements AutoCloseable {
-
- public Problem problem;
- public List> history;
-
- private static PlatformConversation aiScope = null;
-
- public Memory(Problem problem, List> history) {
- this.problem = problem;
- this.history = history;
- checkPlatformConversation();
- }
-
- public Memory addResult(Solutions.Solution result) {
- List> historyUpdate = Stream.concat(this.history.stream(), Stream.of(result)).toList();
- checkPlatformConversation();
- return new Memory<>(this.problem, historyUpdate);
- }
-
- private static void checkPlatformConversation() {
- if(aiScope == null){
- aiScope = OpenAI.conversation();
- }
- }
-
- public static PlatformConversation getAiScope() {
- return aiScope;
- }
-
- public void close(){
- if(aiScope != null) {
- aiScope.close();
- aiScope = null;
- }
- }
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Rendering.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Rendering.java
deleted file mode 100644
index b1fdda157..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Rendering.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.tot;
-
-import java.util.Arrays;
-import java.util.stream.Collectors;
-
-public class Rendering {
-
- public static String trimMargin(String input){
- return Arrays.stream(input.split("\n")).map(String::trim).collect(Collectors.joining("\n"));
- }
-
- public static String truncateText(String answer) {
- return truncateText(answer, 150);
- }
-
- public static String truncateText(String answer, int limit) {
- if(answer == null)
- return "";
- if(answer.length() > limit) {
- answer = answer.substring(0, limit - 3) + "...";
- }
- return answer.replace("\n", " ");
- }
-
- public static String renderHistory(Problems.Memory memory){
- return trimMargin(" ```history \n\n" +
- memory.history.stream()
- .map(Rendering::renderHistoryItem)
- .collect(Collectors.joining("\n")) +
- "```");
- }
-
- private static String renderHistoryItem(Solutions.Solution solution){
- return trimMargin(solution.answer + "\n" +
- solution.reasoning + "\n" +
- (solution.isValid ? "✅" : "❌") + "\n");
- }
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Solutions.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Solutions.java
deleted file mode 100644
index cdbe3cba9..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Solutions.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.tot;
-
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI;
-import com.xebia.functional.xef.prompt.Prompt;
-
-import static com.xebia.functional.xef.java.auto.jdk21.tot.Rendering.renderHistory;
-import static com.xebia.functional.xef.java.auto.jdk21.tot.Rendering.truncateText;
-
-public class Solutions{
-
- static class Solution{
- public String answer;
- public boolean isValid;
- public String reasoning;
-
- public A value;
- }
-
- public static Solution makeSolution(String answer, boolean isValid, String reasoning, B value) {
- Solution solution = new Solution<>();
- solution.isValid = isValid;
- solution.answer = answer;
- solution.reasoning = reasoning;
- solution.value = value;
- return solution;
- }
-
- public static Solution solution(Problems.Memory memory,
- ControlSignals.ControlSignal controlSignal){
- //ai emoji
- System.out.println("\uD83E\uDD16 Generating solution for problem: " + truncateText(memory.problem.description) + "...");
-
- Prompt enhancedPrompt = new Prompt(
- " Given previous history:\n" +
- " " + renderHistory(memory) + "\n" +
- " Given the goal: \n" +
- " ```goal\n" +
- " " + memory.problem.description + " \n" +
- " ```\n" +
- " and considering the guidance: \n" +
- " ```guidance\n" +
- " " + controlSignal.value + "\n" +
- " ```\n" +
- " \n" +
- " Instructions:\n" +
- " \n" +
- " 1. Please provide a comprehensive solution. \n" +
- " 2. Consider all possible scenarios and edge cases. \n" +
- " 3. Ensure your solution is accurate, complete, and unambiguous. \n" +
- " 4. If you are unable to provide a solution, please provide a reason why and set `isValid` to false.\n" +
- " 5. Include citations, references and links at the end to support your solution based on your sources.\n" +
- " 6. Do not provide recommendations, only provide a solution.\n" +
- " 7. when `isValid` is true Include in the `value` field the value of the solution according to the `value` json schema.\n" +
- " 8. If no solution is found set the `value` field to `null`.\n" +
- " 9. If the solution is not valid set the `isValid` field to `false` and the `value` field to `null`.\n" +
- " 10. If the solution is valid set the `isValid` field to `true` and the `value` field to the value of the solution.\n" +
- " \n");
-
- try {
- return Problems.Memory.getAiScope().prompt(OpenAI.FromEnvironment.DEFAULT_SERIALIZATION, enhancedPrompt, Solution.class).get();
- } catch (Exception e) {
- System.err.printf("Solutions.solution enhancedPrompt threw exception: %s - %s\n",
- e.getClass().getName(), e.getMessage());
- return null;
- }
- }
-
-}
diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/util/ConsoleUtil.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/util/ConsoleUtil.java
deleted file mode 100644
index a06678b28..000000000
--- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/util/ConsoleUtil.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.xebia.functional.xef.java.auto.jdk21.util;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-
-public class ConsoleUtil implements AutoCloseable{
-
- private final BufferedReader sysin;
-
- public ConsoleUtil(){
- sysin = new BufferedReader(new InputStreamReader(System.in));
- }
-
- /**
- * Read line from the console (IDE friendly)
- * @return line from console input
- */
- public String readLine() {
- try {
- return sysin.readLine();
- } catch (IOException e) {
- return null;
- }
- }
-
- @Override
- public void close() throws Exception {
- sysin.close();
- }
-}
diff --git a/examples/scala/.scalafmt.conf b/examples/scala/.scalafmt.conf
deleted file mode 100644
index 038d0ede0..000000000
--- a/examples/scala/.scalafmt.conf
+++ /dev/null
@@ -1,36 +0,0 @@
-# tune this file as appropriate to your style! see: https://olafurpg.github.io/scalafmt/#Configuration
-
-version = "3.7.15"
-
-runner.dialect = "scala3"
-
-maxColumn = 150
-
-continuationIndent.callSite = 2
-
-newlines {
- sometimesBeforeColonInMethodReturnType = false
-}
-
-align {
- arrowEnumeratorGenerator = false
- ifWhileOpenParen = false
- openParenCallSite = false
- openParenDefnSite = false
- tokens = ["%", "%%"]
-}
-
-docstrings.style = Asterisk
-
-rewrite {
- rules = [SortImports, RedundantBraces]
- redundantBraces.maxLines = 1
-}
-
-optIn {
- breaksInsideChains = true
-}
-
-project.excludeFilters = [
- "metals.sbt"
-]
diff --git a/examples/scala/build.gradle.kts b/examples/scala/build.gradle.kts
deleted file mode 100644
index 615adf2a5..000000000
--- a/examples/scala/build.gradle.kts
+++ /dev/null
@@ -1,30 +0,0 @@
-@file:Suppress("DSL_SCOPE_VIOLATION")
-
-plugins {
- scala
- alias(libs.plugins.spotless)
-}
-
-java {
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- toolchain { languageVersion = JavaLanguageVersion.of(21) }
-}
-
-dependencies {
- implementation(projects.xefCore)
- implementation(projects.xefScala)
- implementation(projects.xefReasoning)
- implementation(projects.xefOpenai)
- implementation(libs.circe.parser)
- implementation(libs.scala.lang)
- implementation(libs.logback)
-}
-
-tasks.withType().configureEach { useJUnit() }
-
-tasks.withType {
- scalaCompileOptions.additionalParameters = listOf("-Wunused:all", "-Wvalue-discard")
-}
-
-spotless { scala { scalafmt("3.7.15").configFile(".scalafmt.conf") } }
diff --git a/examples/scala/src/main/resources/logback.xml b/examples/scala/src/main/resources/logback.xml
deleted file mode 100644
index 8b62c8b02..000000000
--- a/examples/scala/src/main/resources/logback.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/Simple.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/Simple.scala
deleted file mode 100644
index c9f4b17d1..000000000
--- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/Simple.scala
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.xebia.functional.xef.examples.scala
-
-import com.xebia.functional.xef.scala.conversation.*
-
-@main def runBooks(): Unit = conversation:
- val topic = "functional programming"
- val topBook: String = promptMessage(s"Give me the top-selling book about $topic")
- println(topBook)
- val selectedBooks: List[String] = promptMessages(s"Give me a selection of books about $topic")
- println(selectedBooks.mkString("\n"))
diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/context/serpapi/Simple.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/context/serpapi/Simple.scala
deleted file mode 100644
index fbe40da7e..000000000
--- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/context/serpapi/Simple.scala
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.xebia.functional.xef.examples.scala.context.serpapi
-
-import com.xebia.functional.xef.conversation.llm.openai.*
-import com.xebia.functional.xef.reasoning.serpapi.*
-import com.xebia.functional.xef.scala.conversation.*
-import com.xebia.functional.xef.scala.serialization.*
-import io.circe.Decoder
-
-import java.text.SimpleDateFormat
-import java.util.Date
-
-val openAI: OpenAI = OpenAI.FromEnvironment
-
-val sdf = SimpleDateFormat("dd/M/yyyy")
-def currentDate: String = sdf.format(new Date)
-
-def setContext(query: String)(using conversation: ScalaConversation): Unit =
- addContext(Search(openAI.DEFAULT_CHAT, conversation, 3).search(query).get)
-
-case class BreakingNews(summary: String) derives SerialDescriptor, Decoder
-
-case class MarketNews(news: String, risingStockSymbols: List[String], fallingStockSymbols: List[String]) derives SerialDescriptor, Decoder
-
-case class Estimate(number: Long) derives SerialDescriptor, Decoder
-
-@main def runWeather(): Unit = conversation:
- setContext("Weather in Cádiz, Spain")
- val question = "Knowing this forecast, what clothes do you recommend I should wear if I live in Cádiz?"
- val answer = promptMessage(question)
- println(answer)
-
-@main def runBreakingNews(): Unit = conversation:
- setContext(s"$currentDate COVID News")
- val BreakingNews(summary) = prompt[BreakingNews](s"Write a summary of about 300 words given the provided context.")
- println(summary)
-
-@main def runMarketNews(): Unit = conversation:
- setContext(s"$currentDate Stock market results, rising stocks, falling stocks")
- val news = prompt[MarketNews]("Write a short summary of the stock market results given the provided context.")
- println(news)
-
-@main def runFermiEstimate(): Unit = conversation:
- setContext("Estimate the number of medical needles in the world")
- val Estimate(needlesInWorld) = prompt[Estimate]("Answer the question with an integer number given the provided context.")
- println(s"Needles in world: $needlesInWorld")
diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/context/serpapi/UserQueries.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/context/serpapi/UserQueries.scala
deleted file mode 100644
index 711db19da..000000000
--- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/context/serpapi/UserQueries.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.xebia.functional.xef.examples.scala.context.serpapi
-
-import com.xebia.functional.xef.reasoning.pdf.PDF
-import com.xebia.functional.xef.scala.conversation.*
-import com.xebia.functional.xef.scala.serialization.*
-import io.circe.Decoder
-
-import scala.io.StdIn.readLine
-
-case class AIResponse(answer: String) derives SerialDescriptor, Decoder
-
-val PdfUrl = "https://people.cs.ksu.edu/~schmidt/705a/Scala/Programming-in-Scala.pdf"
-
-@main def runUserQueries(): Unit = conversation:
- val pdf = PDF(openAI.DEFAULT_CHAT, openAI.DEFAULT_SERIALIZATION, summon[ScalaConversation])
- addContext(Array(pdf.readPDFFromUrl.readPDFFromUrl(PdfUrl).get))
- while (true)
- println("Enter your question: ")
- val AIResponse(answer) = prompt[AIResponse](readLine())
- println(s"$answer\n---\n")
diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/images/HybridCity.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/images/HybridCity.scala
deleted file mode 100644
index 1c9a3b4a9..000000000
--- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/images/HybridCity.scala
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.xebia.functional.xef.examples.scala.images
-
-import com.xebia.functional.xef.prompt.Prompt
-import com.xebia.functional.xef.scala.conversation.*
-import com.xebia.functional.xef.scala.serialization.*
-import io.circe.Decoder
-
-@main def runHybridCity(): Unit = conversation:
- val imageUrls = images(Prompt("A hybrid city of Cádiz, Spain and Seattle, US."))
- println(imageUrls)
diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/iteration/AnimalStory.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/iteration/AnimalStory.scala
deleted file mode 100644
index 19e6d433e..000000000
--- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/iteration/AnimalStory.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.xebia.functional.xef.examples.scala.iteration
-
-import com.xebia.functional.xef.prompt.JvmPromptBuilder
-import com.xebia.functional.xef.scala.conversation.*
-import com.xebia.functional.xef.scala.serialization.*
-import io.circe.Decoder
-
-case class Animal(name: String, habitat: String, diet: String) derives SerialDescriptor, Decoder
-case class Invention(name: String, inventor: String, year: Int, purpose: String) derives SerialDescriptor, Decoder
-
-@main def runAnimalStory(): Unit = conversation:
- val animal = prompt[Animal]("A unique animal species")
- val invention = prompt[Invention]("A groundbreaking invention from the 20th century.")
- println(s"Animal: $animal")
- println(s"Invention: $invention")
- val builder = new JvmPromptBuilder()
- .addSystemMessage("You are a writer for a science fiction magazine.")
- .addUserMessage("Write a short story of 200 words that involves the animal and the invention.")
- val story = promptMessage(builder.build)
- println(story)
diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/iteration/ChessGame.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/iteration/ChessGame.scala
deleted file mode 100644
index 42472e1a0..000000000
--- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/iteration/ChessGame.scala
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.xebia.functional.xef.examples.scala.iteration
-
-import com.xebia.functional.xef.prompt.Prompt
-import com.xebia.functional.xef.scala.conversation.*
-import com.xebia.functional.xef.scala.serialization.*
-import io.circe.Decoder
-
-import scala.annotation.tailrec
-
-case class ChessMove(player: String, move: String) derives SerialDescriptor, Decoder
-case class ChessBoard(board: String) derives SerialDescriptor, Decoder
-case class GameState(ended: Boolean = false, winner: Option[String] = None) derives SerialDescriptor, Decoder
-
-@tailrec
-private def chessGame(moves: List[ChessMove] = Nil, gameState: GameState = new GameState)(using ScalaConversation): (String, ChessMove) =
- if !gameState.ended then
- val currentPlayer = if moves.size % 2 == 0 then "Player 1 (White)" else "Player 2 (Black)"
- val previousMoves = moves.map(m => m.player + ":" + m.move).mkString(", ")
- val movePrompt = moves match {
- case Nil => s"""
- |$currentPlayer, you are playing chess and it's your turn.
- |Make your first move:
- """.stripMargin
- case l => s"""
- |$currentPlayer, you are playing chess and it's your turn.
- |Here are the previous moves: $previousMoves
- |Make your next move:
- """.stripMargin
- }
- println(movePrompt)
- val move = prompt[ChessMove](movePrompt)
- println(s"Move is: $move")
- val boardPrompt =
- s"""
- |Given the following chess moves: $previousMoves,
- |generate a chess board on a table with appropriate emoji representations for each move and piece.
- |Add a brief description of the move and its implications.
- """.stripMargin
- val chessBoard = prompt[ChessBoard](boardPrompt)
- println(s"Current board:\n${chessBoard.board}")
- val gameStatePrompt =
- s"""
- |Given the following chess moves: ${moves.mkString(", ")},
- |has the game ended (win, draw, or stalemate)?
- """.stripMargin
- val gameState = prompt[GameState](gameStatePrompt)
- chessGame(moves :+ move, gameState)
- else (gameState.winner.getOrElse("Something went wrong"), moves.last)
-
-@main def runChessGame(): Unit = conversation:
- val (winner, fMove) = chessGame()
- println(s"Game over. Final move: $fMove, Winner: $winner")
diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/serialization/Annotated.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/serialization/Annotated.scala
deleted file mode 100644
index 168599987..000000000
--- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/serialization/Annotated.scala
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.xebia.functional.xef.examples.scala.serialization
-
-import com.xebia.functional.xef.prompt.Prompt
-import com.xebia.functional.xef.scala.conversation.*
-import com.xebia.functional.xef.scala.serialization.*
-import io.circe.Decoder
-
-@Description("A book")
-case class AnnotatedBook(
- @Description("The name of the book") name: String,
- @Description("The author of the book") author: String,
- @Description("A 50 word paragraph with a summary of this book") summary: String
-) derives SerialDescriptor,
- Decoder
-
-@main def runAnnotatedBook(): Unit = conversation:
- val book = prompt[AnnotatedBook]("To Kill a Mockingbird")
- println(book)
diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/serialization/Simple.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/serialization/Simple.scala
deleted file mode 100644
index 2652fd8a3..000000000
--- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/serialization/Simple.scala
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.xebia.functional.xef.examples.scala.serialization
-
-import com.xebia.functional.xef.scala.conversation.*
-import com.xebia.functional.xef.scala.serialization.*
-import io.circe.Decoder
-
-case class AsciiArt(art: String) derives SerialDescriptor, Decoder
-
-case class Book(title: String, author: String, pages: Int) derives SerialDescriptor, Decoder
-
-case class City(population: Int, description: String) derives SerialDescriptor, Decoder
-
-case class Movie(title: String, genre: String, director: String) derives SerialDescriptor, Decoder
-
-case class Recipe(name: String, ingredients: List[String]) derives SerialDescriptor, Decoder
-
-@main def runAsciiArt(): Unit = conversation:
- val AsciiArt(art) = prompt[AsciiArt]("ASCII art of a cat dancing")
- println(art)
-
-@main def runBook(): Unit = conversation:
- val topic = "functional programming"
- val Book(title, author, pages) = prompt[Book](s"Give me the best-selling book about $topic")
- println(s"The book $title is by $author and has $pages pages.")
-
-@main def runMovie(): Unit = conversation:
- val Movie(title, genre, director) = prompt[Movie]("Inception movie genre and director.")
- println(s"The movie $title is a $genre film directed by $director.")
-
-@main def runCities(): Unit = conversation:
- val cadiz = prompt[City]("Cádiz, Spain")
- val seattle = prompt[City]("Seattle, WA")
- println(s"The population of Cádiz is ${cadiz.population} and the population of Seattle is ${seattle.population}.")
-
-@main def runRecipe(): Unit = conversation:
- val Recipe(name, ingredients) = prompt[Recipe]("Recipe for chocolate chip cookies.")
- println(s"The recipe for $name is $ingredients.")
diff --git a/gradle.properties b/gradle.properties
index a0979c287..e42fb3212 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -4,7 +4,7 @@ kotlin.native.cacheKind=none
project.group=com.xebia
pom.name=xef
-pom.description=Building applications with LLMs through composability, in Kotlin and Scala
+pom.description=Building applications with LLMs through composability in Kotlin
pom.url=https://github.com/xebia-functional/xef
pom.license.name=The Apache Software License, Version 2.0
pom.license.url=https://www.apache.org/licenses/LICENSE-2.0.txt
@@ -21,5 +21,3 @@ systemProp.org.gradle.unsafe.kotlin.assignment=true
# Workaround to disable Dokka setup from Arrow Gradle Config
dokkaEnabled=false
-
-scalaVersion=3.3.1
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 8c36b5552..840ac3010 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -20,11 +20,6 @@ dokka = "1.9.10"
logback = "1.4.11"
node-gradle = "7.0.1"
kotlinx-coroutines = "1.7.3"
-scalaMultiversion = "2.0.6"
-circe = "0.14.6"
-catsEffect = "3.6-0142603"
-munit = "0.7.29"
-munitCatsEffect = "1.0.7"
scrapeit = "1.1.5"
rssreader = "3.5.0"
lucene = "9.8.0"
@@ -33,7 +28,6 @@ junit = "5.10.0"
pdfbox = "3.0.0"
mysql = "8.0.33"
semverGradle = "0.5.0-rc.5"
-scala = "3.3.1"
openai-client-version = "3.5.1"
gpt4all-java = "1.1.5"
ai-djl = "0.24.0"
@@ -104,11 +98,6 @@ hikari = { module = "com.zaxxer:HikariCP", version.ref = "hikari" }
postgresql = { module = "org.postgresql:postgresql", version.ref = "postgresql" }
testcontainers-postgresql = { module = "org.testcontainers:postgresql", version.ref = "testcontainers" }
logback = { module = "ch.qos.logback:logback-classic", version.ref = "logback" }
-circe = { module = "io.circe:circe-generic_3", version.ref = "circe" }
-circe-parser = { module = "io.circe:circe-parser_3", version.ref = "circe" }
-cats-effect = { module = "org.typelevel:cats-effect_3", version.ref = "catsEffect" }
-munit-core = { module = "org.scalameta:munit_3", version.ref = "munit" }
-munit-cats-effect = { module = "org.typelevel:munit-cats-effect-3_3", version.ref = "munitCatsEffect" }
skrape = { module = "it.skrape:skrapeit", version.ref = "scrapeit" }
skrape-browser-fetcher = { module = "it.skrape:skrapeit-browser-fetcher", version.ref = "scrapeit" }
skrape-async-fetcher = { module = "it.skrape:skrapeit-asyn-fetcher", version.ref = "scrapeit" }
@@ -118,7 +107,6 @@ lucene-queries = { module = "org.apache.lucene:lucene-queries", version.ref = "l
assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" }
apache-pdf-box = { module = "org.apache.pdfbox:pdfbox", version.ref = "pdfbox" }
jdbc-mysql-connector = { module = "mysql:mysql-connector-java", version.ref = "mysql" }
-scala-lang = { module = "org.scala-lang:scala3-library_3", version.ref = "scala" }
openai-client = { module = "com.aallam.openai:openai-client", version.ref = "openai-client-version" }
gpt4all-java-bindings = { module = "com.hexadevlabs:gpt4all-java-binding", version.ref = "gpt4all-java" }
ai-djl-huggingface-tokenizers = { module = "ai.djl.huggingface:tokenizers", version.ref = "ai-djl" }
@@ -155,7 +143,6 @@ spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
arrow-gradle-nexus = { id = "io.arrow-kt.arrow-gradle-config-nexus", version.ref = "arrowGradle" }
arrow-gradle-publish = { id = "io.arrow-kt.arrow-gradle-config-publish", version.ref = "arrowGradle" }
-scala-multiversion = { id = "com.adtran.scala-multiversion-plugin", version.ref = "scalaMultiversion" }
kotest-multiplatform = { id = "io.kotest.multiplatform", version.ref = "kotest" }
semver-gradle = { id="com.javiersc.semver", version.ref="semverGradle" }
suspend-transform-plugin = { id="love.forte.plugin.suspend-transform", version.ref="suspend-transform" }
diff --git a/java/README.md b/java/README.md
deleted file mode 100644
index 380f6937b..000000000
--- a/java/README.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# xef.ai for Java
-
-Build the project locally, from the project root:
-
-```shell
-./gradlew build
-```
-
-## Java Spotless
-
-The Java module uses the [spotless](https://github.com/diffplug/spotless/tree/main/plugin-gradle#java) plugin.
-Therefore, the previous command (`./gradlew build`) will fail in case there is any formatting issue. To apply format, you can run the following command:
-
-```shell
-./gradlew spotlessApply
-```
-
-## Examples
-
-Check out some use case at the [Java examples](../examples/java) folder.
-
-### Running the Examples
-
-How to run the examples (from IntelliJ IDEA):
-
-* Set Env variable: `OPENAI_TOKEN=xxx`
diff --git a/java/build.gradle.kts b/java/build.gradle.kts
deleted file mode 100644
index 99ba21ab2..000000000
--- a/java/build.gradle.kts
+++ /dev/null
@@ -1,32 +0,0 @@
-@file:Suppress("DSL_SCOPE_VIOLATION")
-
-plugins {
- `java-library`
- `maven-publish`
- signing
- `xef-java-publishing-conventions`
- alias(libs.plugins.semver.gradle)
- alias(libs.plugins.spotless)
-}
-
-dependencies {
- api(projects.xefCore)
- api(projects.xefOpenai)
- api(projects.xefPdf)
- api(projects.xefSql)
- api(libs.jdbc.mysql.connector)
- api(libs.jackson)
- api(libs.jackson.schema)
- api(libs.jackson.schema.jakarta)
- api(libs.jakarta.validation)
- api(libs.kotlinx.coroutines.reactive)
-}
-
-java {
- withJavadocJar()
- withSourcesJar()
-}
-
-tasks.withType().configureEach { useJUnit() }
-
-tasks.withType { dependsOn(tasks.withType()) }
diff --git a/java/src/main/java/com/xebia/functional/xef/java/auto/Empty.java b/java/src/main/java/com/xebia/functional/xef/java/auto/Empty.java
deleted file mode 100644
index 82c339a6b..000000000
--- a/java/src/main/java/com/xebia/functional/xef/java/auto/Empty.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.xebia.functional.xef.java.auto;
-
-/**
- * Module placeholder
- */
-public class Empty {
-}
diff --git a/scala/.scalafmt.conf b/scala/.scalafmt.conf
deleted file mode 100644
index 038d0ede0..000000000
--- a/scala/.scalafmt.conf
+++ /dev/null
@@ -1,36 +0,0 @@
-# tune this file as appropriate to your style! see: https://olafurpg.github.io/scalafmt/#Configuration
-
-version = "3.7.15"
-
-runner.dialect = "scala3"
-
-maxColumn = 150
-
-continuationIndent.callSite = 2
-
-newlines {
- sometimesBeforeColonInMethodReturnType = false
-}
-
-align {
- arrowEnumeratorGenerator = false
- ifWhileOpenParen = false
- openParenCallSite = false
- openParenDefnSite = false
- tokens = ["%", "%%"]
-}
-
-docstrings.style = Asterisk
-
-rewrite {
- rules = [SortImports, RedundantBraces]
- redundantBraces.maxLines = 1
-}
-
-optIn {
- breaksInsideChains = true
-}
-
-project.excludeFilters = [
- "metals.sbt"
-]
diff --git a/scala/README.md b/scala/README.md
deleted file mode 100644
index e74c18873..000000000
--- a/scala/README.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# xef.ai for Scala
-
-Build the project locally, from the project root:
-
-```shell
-./gradlew build
-```
-
-## Scalafmt
-
-The Scala module uses the [spotless](https://github.com/diffplug/spotless/tree/main/plugin-gradle#scala) plugin.
-Therefore, the previous command (`./gradlew build`) will fail if there are any formatting issues.
-To apply formatting, you can run the following command:
-
-```shell
-./gradlew spotlessApply
-```
-
-## Examples
-
-Check out some use case at the [Scala examples](../examples/scala) folder.
-
-### Running the Examples
-
-How to run the examples (from IntelliJ IDEA):
-
-* Set Java version 20 or above
-* Set VM options: `--enable-preview` (if using Java 20 specifically)
-* Set Env variable: `OPENAI_TOKEN=xxx`
diff --git a/scala/build.gradle.kts b/scala/build.gradle.kts
deleted file mode 100644
index e17e0c4c4..000000000
--- a/scala/build.gradle.kts
+++ /dev/null
@@ -1,38 +0,0 @@
-@file:Suppress("DSL_SCOPE_VIOLATION")
-
-plugins {
- scala
- `maven-publish`
- signing
- alias(libs.plugins.semver.gradle)
- alias(libs.plugins.spotless)
- `xef-scala-publishing-conventions`
-}
-
-dependencies {
- implementation(projects.xefCore)
- implementation(projects.xefOpenai)
- implementation(libs.kotlinx.coroutines.reactive)
- // TODO split to separate Scala library
- implementation(projects.xefPdf)
- implementation(libs.circe.parser)
- implementation(libs.circe)
- implementation(libs.scala.lang)
- implementation(libs.logback)
- testImplementation(libs.munit.core)
-}
-
-java {
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- toolchain { languageVersion = JavaLanguageVersion.of(21) }
- withSourcesJar()
-}
-
-tasks.withType().configureEach { useJUnit() }
-
-tasks.withType {
- scalaCompileOptions.additionalParameters = listOf("-Wunused:all", "-Wvalue-discard")
-}
-
-spotless { scala { scalafmt("3.7.15").configFile(".scalafmt.conf") } }
diff --git a/scala/src/main/resources/logback.xml b/scala/src/main/resources/logback.xml
deleted file mode 100644
index 8b62c8b02..000000000
--- a/scala/src/main/resources/logback.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/scala/src/main/scala/com/xebia/functional/xef/scala/conversation/package.scala b/scala/src/main/scala/com/xebia/functional/xef/scala/conversation/package.scala
deleted file mode 100644
index d65b83efa..000000000
--- a/scala/src/main/scala/com/xebia/functional/xef/scala/conversation/package.scala
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.xebia.functional.xef.scala.conversation
-
-import com.xebia.functional.xef.conversation.*
-import com.xebia.functional.xef.conversation.llm.openai.*
-import com.xebia.functional.xef.conversation.llm.openai.OpenAI.FromEnvironment.*
-import com.xebia.functional.xef.llm.*
-import com.xebia.functional.xef.llm.models.images.*
-import com.xebia.functional.xef.metrics.*
-import com.xebia.functional.xef.prompt.Prompt
-import com.xebia.functional.xef.scala.serialization.*
-import com.xebia.functional.xef.store.*
-import io.circe.Decoder
-import io.circe.parser.parse
-import org.reactivestreams.*
-
-import java.util.UUID.*
-import java.util.concurrent.LinkedBlockingQueue
-import scala.jdk.CollectionConverters.*
-
-class ScalaConversation(store: VectorStore, metric: Metric, conversationId: ConversationId) extends JVMConversation(store, metric, conversationId)
-
-def addContext(context: Array[String])(using conversation: ScalaConversation): Unit =
- conversation.addContextFromArray(context).join()
-
-def prompt[A: Decoder: SerialDescriptor](prompt: Prompt, chat: ChatWithFunctions = DEFAULT_SERIALIZATION)(using conversation: ScalaConversation): A =
- conversation.prompt(chat, prompt, chat.chatFunction(SerialDescriptor[A].serialDescriptor), fromJson).join()
-
-def promptMessage(prompt: Prompt, chat: Chat = DEFAULT_CHAT)(using conversation: ScalaConversation): String =
- conversation.promptMessage(chat, prompt).join()
-
-def promptMessages(prompt: Prompt, chat: Chat = DEFAULT_CHAT)(using conversation: ScalaConversation): List[String] =
- conversation.promptMessages(chat, prompt).join().asScala.toList
-
-def promptStreaming(prompt: Prompt, chat: Chat = DEFAULT_CHAT)(using conversation: ScalaConversation): LazyList[String] =
- val publisher = conversation.promptStreamingToPublisher(chat, prompt)
- val queue = new LinkedBlockingQueue[String]()
- publisher.subscribe(new Subscriber[String]: // TODO change to fs2 or similar
- def onSubscribe(s: Subscription): Unit = s.request(Long.MaxValue)
- def onNext(t: String): Unit = queue.add(t); ()
- def onError(t: Throwable): Unit = throw t
- def onComplete(): Unit = ()
- )
- LazyList.continually(queue.take)
-
-def prompt[A: Decoder: SerialDescriptor](message: String)(using ScalaConversation): A =
- prompt(Prompt(message))
-
-def promptMessage(message: String)(using ScalaConversation): String =
- promptMessage(Prompt(message))
-
-def promptMessages(message: String)(using ScalaConversation): List[String] =
- promptMessages(Prompt(message))
-
-def promptStreaming(message: String)(using ScalaConversation): LazyList[String] =
- promptStreaming(Prompt(message))
-
-def images(prompt: Prompt, images: Images = DEFAULT_IMAGES, numberImages: Int = 1, size: String = "1024x1024")(using
- conversation: ScalaConversation
-): ImagesGenerationResponse =
- conversation.images(images, prompt, numberImages, size).join()
-
-def conversation[A](block: ScalaConversation ?=> A, id: ConversationId = ConversationId(randomUUID.toString)): A =
- block(using ScalaConversation(LocalVectorStore(DEFAULT_EMBEDDING), LogsMetric(), id))
-
-private def fromJson[A: Decoder]: FromJson[A] = json => parse(json).flatMap(Decoder[A].decodeJson(_)).fold(throw _, identity)
diff --git a/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/KotlinXSerializers.scala b/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/KotlinXSerializers.scala
deleted file mode 100644
index 30aa05e4a..000000000
--- a/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/KotlinXSerializers.scala
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.xebia.functional.xef.scala.serialization
-
-import kotlin.jvm.internal.*
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.builtins.BuiltinSerializersKt
-import kotlinx.serialization.builtins.BuiltinSerializersKt.serializer
-
-object KotlinXSerializers:
- val int: KSerializer[java.lang.Integer] = serializer(IntCompanionObject.INSTANCE)
- val string: KSerializer[String] = serializer(StringCompanionObject.INSTANCE)
- val boolean: KSerializer[java.lang.Boolean] = serializer(BooleanCompanionObject.INSTANCE)
- val double: KSerializer[java.lang.Double] = serializer(DoubleCompanionObject.INSTANCE)
- val float: KSerializer[java.lang.Float] = serializer(FloatCompanionObject.INSTANCE)
- val long: KSerializer[java.lang.Long] = serializer(LongCompanionObject.INSTANCE)
- val short: KSerializer[java.lang.Short] = serializer(ShortCompanionObject.INSTANCE)
- val byte: KSerializer[java.lang.Byte] = serializer(ByteCompanionObject.INSTANCE)
- val char: KSerializer[Character] = serializer(CharCompanionObject.INSTANCE)
- val unit: KSerializer[kotlin.Unit] = serializer(kotlin.Unit.INSTANCE)
diff --git a/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptor.scala b/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptor.scala
deleted file mode 100644
index 9b574065a..000000000
--- a/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptor.scala
+++ /dev/null
@@ -1,116 +0,0 @@
-package com.xebia.functional.xef.scala.serialization
-
-import com.xebia.functional.xef.conversation.jvm.Description as JvmDescription
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.descriptors.{SerialDescriptor as KtSerialDescriptor, SerialKind, StructureKind}
-import kotlinx.serialization.encoding.{Decoder as KtDecoder, Encoder as KtEncoder}
-
-import java.lang.annotation.Annotation
-import java.util
-import scala.annotation.meta.*
-import scala.compiletime.*
-import scala.deriving.*
-import scala.jdk.CollectionConverters.*
-import scala.quoted.*
-import scala.reflect.ClassTag
-
-trait SerialDescriptor[A]:
- def serialDescriptor: KtSerialDescriptor
- def kserializer: KSerializer[A] = new KSerializer[A]:
- override def getDescriptor: KtSerialDescriptor = serialDescriptor
- override def serialize(encoder: KtEncoder, t: A): Unit = ??? // TODO should we implement this?
- override def deserialize(decoder: KtDecoder): A = ??? // TODO should we implement this?
-
-object SerialDescriptor extends SerialDescriptorInstances:
- def apply[A](using ev: SerialDescriptor[A]): SerialDescriptor[A] = ev
-
- private inline def getElemsLabel[T <: Tuple]: List[String] = inline erasedValue[T] match
- case _: EmptyTuple => Nil
- case _: (h *: t) => erasedValue[h].toString :: getElemsLabel[t]
-
- private inline def getSerialDescriptor[T <: Tuple]: List[KtSerialDescriptor] = inline erasedValue[T] match
- case _: EmptyTuple => Nil
- case _: (String *: t) => KotlinXSerializers.string.getDescriptor :: getSerialDescriptor[t]
- case _: (Boolean *: t) => KotlinXSerializers.boolean.getDescriptor :: getSerialDescriptor[t]
- case _: (Byte *: t) => KotlinXSerializers.byte.getDescriptor :: getSerialDescriptor[t]
- case _: (Char *: t) => KotlinXSerializers.char.getDescriptor :: getSerialDescriptor[t]
- case _: (Double *: t) => KotlinXSerializers.double.getDescriptor :: getSerialDescriptor[t]
- case _: (Float *: t) => KotlinXSerializers.float.getDescriptor :: getSerialDescriptor[t]
- case _: (Int *: t) => KotlinXSerializers.int.getDescriptor :: getSerialDescriptor[t]
- case _: (Long *: t) => KotlinXSerializers.long.getDescriptor :: getSerialDescriptor[t]
- case _: (Short *: t) => KotlinXSerializers.short.getDescriptor :: getSerialDescriptor[t]
- case _: (Unit *: t) => KotlinXSerializers.unit.getDescriptor :: getSerialDescriptor[t]
- case _: (h *: t) => summonInline[SerialDescriptor[h]].serialDescriptor :: getSerialDescriptor[t]
-
- inline final def derived[A](using m: Mirror.Of[A]): SerialDescriptor[A] =
- val fieldAnnotationMap = getFieldAnnotationsMap[A]
- new SerialDescriptor[A]:
- val serialDescriptorImpl: KtSerialDescriptor = new KtSerialDescriptor:
- val labels = getElemsLabel[m.MirroredElemLabels]
- val serialDescriptors = getSerialDescriptor[m.MirroredElemTypes]
-
- override def getElementIndex(name: String): Int = labels.indexOf(name)
-
- // We're going to ignore annotations for now, it's not relevant for JsonSchema
- override def getElementAnnotations(index: Int): util.List[Annotation] =
- val fieldName = labels(index)
- val annotations = fieldAnnotationMap(fieldName)
- annotations.filter(_.isInstanceOf[Description]).asJava.asInstanceOf[util.List[Annotation]]
-
- override def getElementDescriptor(index: Int): KtSerialDescriptor = serialDescriptors(index)
-
- // We're going to ignore annotations for now, it's not relevant for JsonSchema
- override def getAnnotations: util.List[Annotation] =
- val annotations = getStaticAnnotations[A]
- annotations.filter(_.isInstanceOf[Description]).asJava.asInstanceOf[util.List[Annotation]]
-
- override def getElementsCount: Int = labels.size
-
- override def isInline: Boolean = false
-
- // Is the element wrapped in `Option`, or is a union with `Null`?
- override def isNullable: Boolean = false
-
- override def getKind: SerialKind = StructureKind.CLASS.INSTANCE
-
- override def getSerialName: String = constValue[m.MirroredLabel]
-
- override def getElementName(i: Int): String = labels(i)
-
- // Does the element at the given index have a default value, or is it wrapped in `Option`, or is a union with `Null`?
- override def isElementOptional(index: Int): Boolean = false
-
- def serialDescriptor: KtSerialDescriptor = serialDescriptorImpl
-
-inline def getStaticAnnotations[A]: List[Any] = ${ getAnnotationsImpl[A] }
-
-def getAnnotationsImpl[A: Type](using Quotes): Expr[List[Any]] =
- import quotes.reflect.*
- val annotations = TypeRepr.of[A].typeSymbol.annotations.map(_.asExpr)
- Expr.ofList(annotations)
-
-inline def getFieldAnnotationsMap[A]: Map[String, List[Any]] =
- ${ getFieldAnnotationsMapImpl[A] }
-
-def getFieldAnnotationsMapImpl[A: Type](using Quotes): Expr[Map[String, List[Any]]] =
- import quotes.reflect.*
- // Extract the fields from the type
- val fields = TypeRepr.of[A].typeSymbol.primaryConstructor.paramSymss.flatten
- // For each field, extract its name and annotations
- val fieldAnnotationsMap: List[Expr[(String, List[Any])]] = fields.map: field =>
- val fieldName = Expr(field.name)
- val annotations = Expr.ofList(field.annotations.map(_.asExpr))
- '{ ($fieldName, $annotations) }
- // Convert list of (String, List[Any]) tuples to a map
- fieldAnnotationsMap match
- case Nil => '{ Map.empty[String, List[Any]] }
- case _ =>
- val mapExpr = Expr.ofList(fieldAnnotationsMap)
- '{ $mapExpr.toMap }
-
-/**
- * A scala annotation that maps to the jvm description annotation
- */
-class Description(description: String) extends JvmDescription with scala.annotation.StaticAnnotation:
- override def value(): String = description
- override def annotationType(): Class[_ <: Annotation] = classOf[JvmDescription]
diff --git a/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptorInstances.scala b/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptorInstances.scala
deleted file mode 100644
index ee761f27c..000000000
--- a/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptorInstances.scala
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.xebia.functional.xef.scala.serialization
-
-import kotlin.jvm.internal.Reflection
-import kotlin.reflect.KClass
-import kotlinx.serialization.builtins.BuiltinSerializersKt
-
-import scala.compiletime.summonInline
-import scala.reflect.ClassTag
-
-class SerialDescriptorInstances:
-
- given [T: SerialDescriptor]: SerialDescriptor[Option[T]] = new SerialDescriptor[Option[T]]:
- def serialDescriptor = BuiltinSerializersKt.getNullable(SerialDescriptor[T].kserializer).getDescriptor
-
- given [T: ClassTag: SerialDescriptor]: SerialDescriptor[Array[T]] = new SerialDescriptor[Array[T]]:
- def serialDescriptor =
- val kClass = Reflection.createKotlinClass(summonInline[ClassTag[T]].runtimeClass).asInstanceOf[KClass[T]]
- BuiltinSerializersKt.ArraySerializer(kClass, SerialDescriptor[T].kserializer).getDescriptor
-
- given [T: SerialDescriptor]: SerialDescriptor[List[T]] = new SerialDescriptor[List[T]]:
- def serialDescriptor = BuiltinSerializersKt.ListSerializer(SerialDescriptor[T].kserializer).getDescriptor
-
- given [T: SerialDescriptor]: SerialDescriptor[Seq[T]] = new SerialDescriptor[Seq[T]]:
- def serialDescriptor = BuiltinSerializersKt.ListSerializer(SerialDescriptor[T].kserializer).getDescriptor
-
- given [T: SerialDescriptor]: SerialDescriptor[Vector[T]] = new SerialDescriptor[Vector[T]]:
- def serialDescriptor = BuiltinSerializersKt.ListSerializer(SerialDescriptor[T].kserializer).getDescriptor
-
- given [T: SerialDescriptor]: SerialDescriptor[Set[T]] = new SerialDescriptor[Set[T]]:
- def serialDescriptor = BuiltinSerializersKt.SetSerializer(SerialDescriptor[T].kserializer).getDescriptor
-
- given [K: SerialDescriptor, V: SerialDescriptor]: SerialDescriptor[Map[K, V]] = new SerialDescriptor[Map[K, V]]:
- def serialDescriptor =
- BuiltinSerializersKt.MapSerializer(SerialDescriptor[K].kserializer, SerialDescriptor[V].kserializer).getDescriptor
-
- given SerialDescriptor[Boolean] = new SerialDescriptor[Boolean]:
- def serialDescriptor = KotlinXSerializers.boolean.getDescriptor
-
- given SerialDescriptor[Byte] = new SerialDescriptor[Byte]:
- def serialDescriptor = KotlinXSerializers.byte.getDescriptor
-
- given SerialDescriptor[Char] = new SerialDescriptor[Char]:
- def serialDescriptor = KotlinXSerializers.char.getDescriptor
-
- given SerialDescriptor[Double] = new SerialDescriptor[Double]:
- def serialDescriptor = KotlinXSerializers.double.getDescriptor
-
- given SerialDescriptor[Float] = new SerialDescriptor[Float]:
- def serialDescriptor = KotlinXSerializers.float.getDescriptor
-
- given SerialDescriptor[Int] = new SerialDescriptor[Int]:
- def serialDescriptor = KotlinXSerializers.int.getDescriptor
-
- given SerialDescriptor[Long] = new SerialDescriptor[Long]:
- def serialDescriptor = KotlinXSerializers.long.getDescriptor
-
- given SerialDescriptor[Short] = new SerialDescriptor[Short]:
- def serialDescriptor = KotlinXSerializers.short.getDescriptor
-
- given SerialDescriptor[String] = new SerialDescriptor[String]:
- def serialDescriptor = KotlinXSerializers.string.getDescriptor
-
- given SerialDescriptor[Unit] = new SerialDescriptor[Unit]:
- def serialDescriptor = KotlinXSerializers.unit.getDescriptor
diff --git a/scala/src/test/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptorSpec.scala b/scala/src/test/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptorSpec.scala
deleted file mode 100644
index 4c103b6e1..000000000
--- a/scala/src/test/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptorSpec.scala
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.xebia.functional.xef.scala.serialization
-
-import cats.syntax.either.*
-import kotlinx.serialization.builtins.BuiltinSerializersKt
-import munit.FunSuite
-
-import scala.collection.immutable.HashSet
-import scala.compiletime.summonInline
-import scala.reflect.ClassTag
-
-class SerialDescriptorSpec extends FunSuite:
-
- test("Should create a SerialDescriptor for a simple case class") {
- final case class Person(age: Int, name: String) derives SerialDescriptor
- assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight)
- }
-
- test("Should create a SerialDescriptor for a simple case class with optional fields") {
- final case class Person(age: Int, name: String, id: Option[Long]) derives SerialDescriptor
- assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight)
- }
-
- test("Should create a SerialDescriptor for a simple case class with set and list fields") {
- final case class Person(age: Int, name: String, siblingNames: Set[String], nationality: List[String]) derives SerialDescriptor
- assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight)
- }
-
- test("Should create a SerialDescriptor for a simple case class with a list case class") {
- final case class Pet(age: Int, name: String) derives SerialDescriptor
- final case class Person(age: Int, name: String, pets: List[Pet]) derives SerialDescriptor
-
- assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight)
- }
-
- test("Should create a SerialDescriptor for a simple case class with seq and vector fields") {
- final case class Person(age: Int, name: String, other1: Seq[Byte], other2: Vector[Short]) derives SerialDescriptor
- assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight)
- }
-
- test("Should create a SerialDescriptor for a simple case class with an array field") {
- final case class Person(other: Array[Double]) derives SerialDescriptor
- assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight)
- }
-
- test("Should create a SerialDescriptor for a simple case class with map fields") {
- final case class Person(age: Int, name: String, alias: Map[String, String]) derives SerialDescriptor
- assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight)
- }
-
- test("Should create a SerialDescriptor for a simple case class with HashSet field, providing a custom given") {
- given [T: SerialDescriptor]: SerialDescriptor[HashSet[T]] = new SerialDescriptor[HashSet[T]]:
- def serialDescriptor = BuiltinSerializersKt.SetSerializer(SerialDescriptor[T].kserializer).getDescriptor
- final case class Person(age: Int, name: String, alias: HashSet[String]) derives SerialDescriptor
- assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight)
- }
-
- test("Should create a SerialDescriptor for a composite case class") {
- final case class Person(age: Int, name: PersonName) derives SerialDescriptor
- final case class PersonName(firstName: String, lastName: String) derives SerialDescriptor
- assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight)
- }
-
- test("Should create a SerialDescriptor for a composite (level 2) case class") {
- final case class Person(age: Int, placeOfBirth: PlaceOfBirth) derives SerialDescriptor
- final case class PlaceOfBirth(city: String, country: Country) derives SerialDescriptor
- final case class Country(country: String) derives SerialDescriptor
- assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight)
- }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index aaaf34756..5842a6bca 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -68,30 +68,9 @@ include("xef-kotlin-examples")
project(":xef-kotlin-examples").projectDir = file("examples/kotlin")
//
-//
-include("xef-scala-examples")
-project(":xef-scala-examples").projectDir = file("examples/scala")
-
-include("xef-scala")
-project(":xef-scala").projectDir = file("scala")
-//
-
-//
-include("xef-java")
-project(":xef-java").projectDir = file("java")
-
-include("xef-java-examples")
-project(":xef-java-examples").projectDir = file("examples/java")
-//
-
-//
include("xef-reasoning")
project(":xef-reasoning").projectDir = file("reasoning")
-include("xef-java-examples")
-project(":xef-java-examples").projectDir = file("examples/java")
-//
-
//
include("xef-server")
project(":xef-server").projectDir = file("server")