Skip to content

Commit

Permalink
Project updated to use kotlin official code style everywhere (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
morisil authored Jan 8, 2025
1 parent 441746d commit 78d707c
Show file tree
Hide file tree
Showing 26 changed files with 1,918 additions and 1,964 deletions.
22 changes: 11 additions & 11 deletions .github/workflows/build-branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ jobs:
build_branch:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/[email protected]
- name: Checkout sources
uses: actions/[email protected]

- name: Setup Java
uses: actions/[email protected]
with:
distribution: 'temurin'
java-version: 23
- name: Setup Java
uses: actions/[email protected]
with:
distribution: 'temurin'
java-version: 23

- name: Setup Gradle
uses: gradle/actions/[email protected]
- name: Setup Gradle
uses: gradle/actions/[email protected]

- name: Build
run: ./gradlew build
- name: Build
run: ./gradlew build
28 changes: 14 additions & 14 deletions .github/workflows/build-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ jobs:
build_main:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/[email protected]
- name: Checkout sources
uses: actions/[email protected]

- name: Setup Java
uses: actions/[email protected]
with:
distribution: 'temurin'
java-version: 23
- name: Setup Java
uses: actions/[email protected]
with:
distribution: 'temurin'
java-version: 23

- name: Setup Gradle
uses: gradle/actions/[email protected]
- name: Setup Gradle
uses: gradle/actions/[email protected]

- name: Build
run: ./gradlew build sourcesJar dokkaGeneratePublicationHtml publish
env:
ORG_GRADLE_PROJECT_githubActor: ${{ secrets.GITHUBACTOR }}
ORG_GRADLE_PROJECT_githubToken: ${{ secrets.GITHUBTOKEN }}
- name: Build
run: ./gradlew build sourcesJar dokkaGeneratePublicationHtml publish
env:
ORG_GRADLE_PROJECT_githubActor: ${{ secrets.GITHUBACTOR }}
ORG_GRADLE_PROJECT_githubToken: ${{ secrets.GITHUBTOKEN }}
80 changes: 40 additions & 40 deletions .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Build release
on:
release:
types: [published]
types: [ published ]
jobs:
build_release:
runs-on: ubuntu-latest
Expand All @@ -10,49 +10,49 @@ jobs:
# added or changed files to the repository.
contents: write
steps:
- name: Write release version
run: |
VERSION=${GITHUB_REF_NAME#v}
echo Version: $VERSION
echo "VERSION=$VERSION" >> $GITHUB_ENV
- name: Write release version
run: |
VERSION=${GITHUB_REF_NAME#v}
echo Version: $VERSION
echo "VERSION=$VERSION" >> $GITHUB_ENV
- name: Checkout sources
uses: actions/[email protected]
with:
ref: ${{ github.head_ref }}
fetch-depth: 0
- name: Checkout sources
uses: actions/[email protected]
with:
ref: ${{ github.head_ref }}
fetch-depth: 0

- name: Setup Java
uses: actions/[email protected]
with:
distribution: 'temurin'
java-version: 23
- name: Setup Java
uses: actions/[email protected]
with:
distribution: 'temurin'
java-version: 23

- name: Setup Gradle
uses: gradle/actions/[email protected]
- name: Setup Gradle
uses: gradle/actions/[email protected]

- name: Build
env:
ORG_GRADLE_PROJECT_githubActor: ${{ secrets.GITHUBACTOR }}
ORG_GRADLE_PROJECT_githubToken: ${{ secrets.GITHUBTOKEN }}
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }}
ORG_GRADLE_PROJECT_sonatypeUser: ${{ secrets.SONATYPE_USER }}
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: ./gradlew -Pversion=$VERSION build sourcesJar dokkaGeneratePublicationHtml publishToSonatype closeAndReleaseSonatypeStagingRepository
- name: Build
env:
ORG_GRADLE_PROJECT_githubActor: ${{ secrets.GITHUBACTOR }}
ORG_GRADLE_PROJECT_githubToken: ${{ secrets.GITHUBTOKEN }}
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }}
ORG_GRADLE_PROJECT_sonatypeUser: ${{ secrets.SONATYPE_USER }}
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: ./gradlew -Pversion=$VERSION build sourcesJar dokkaGeneratePublicationHtml publishToSonatype closeAndReleaseSonatypeStagingRepository

- name: Checkout main branch
uses: actions/[email protected]
with:
ref: main
fetch-depth: 0
- name: Checkout main branch
uses: actions/[email protected]
with:
ref: main
fetch-depth: 0

- name: Update README
run: sh .github/scripts/update-readme-version.sh
- name: Update README
run: sh .github/scripts/update-readme-version.sh

- name: Commit README
uses: stefanzweifel/[email protected]
with:
commit_message: Dependency version in README.md updated to ${{ env.VERSION }}
file_pattern: 'README.md'
- name: Commit README
uses: stefanzweifel/[email protected]
with:
commit_message: Dependency version in README.md updated to ${{ env.VERSION }}
file_pattern: 'README.md'
2 changes: 1 addition & 1 deletion .github/workflows/updater.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name: GitHub Actions Version Updater
on:
schedule:
# Automatically run on every Sunday
- cron: '0 0 * * 0'
- cron: '0 0 * * 0'

jobs:
build:
Expand Down
2 changes: 1 addition & 1 deletion .idea/copyright/apache2_0.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

89 changes: 30 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# xemantic-ai-tool-schema

A Kotlin multiplatform JSON Schema library. Useful for AI and LLMs'
[tool use](https://docs.anthropic.com/en/docs/build-with-claude/tool-use)
([function calling](https://platform.openai.com/docs/guides/function-calling)),
as it generates JSON Schema for Kotlin `@Serializable` classes.
A Kotlin multiplatform JSON Schema library. Useful for AI and LLMs' [tool use](https://docs.anthropic.com/en/docs/build-with-claude/tool-use) ([function calling](https://platform.openai.com/docs/guides/function-calling)), as it generates JSON Schema for Kotlin `@Serializable` classes.

[<img alt="Maven Central Version" src="https://img.shields.io/maven-central/v/com.xemantic.ai/xemantic-ai-tool-schema">](https://central.sonatype.com/namespace/com.xemantic.ai)
[<img alt="GitHub Release Date" src="https://img.shields.io/github/release-date/xemantic/xemantic-ai-tool-schema">](https://github.com/xemantic/xemantic-ai-tool-schema/releases)
Expand All @@ -26,45 +23,31 @@ as it generates JSON Schema for Kotlin `@Serializable` classes.

## Why?

This library was created to fulfill the need of agentic AI projects created by
[xemantic](https://xemantic.com/). In particular:
This library was created to fulfill the need of agentic AI projects created by [xemantic](https://xemantic.com/). In particular:

* [anthropic-sdk-kotlin](https://github.com/xemantic/anthropic-sdk-kotlin) - an unofficial Kotlin multiplatform variant
of [Anthropic SDK](https://docs.anthropic.com/en/api/client-sdks).
* [anthropic-sdk-kotlin](https://github.com/xemantic/anthropic-sdk-kotlin) - an unofficial Kotlin multiplatform variant of [Anthropic SDK](https://docs.anthropic.com/en/api/client-sdks).
* [claudine](https://github.com/xemantic/claudine) - AI Agent build on top of this SDK.

These projects are heavily dependent on
[tool use](https://docs.anthropic.com/en/docs/build-with-claude/tool-use)
([function calling](https://platform.openai.com/docs/guides/function-calling)) functionality
provided by many Large Language Models. Thanks to `xemantic-ai-tool-schema`, a Kotlin class,
with possible additional constraints, can be automatically instantiated from
the JSON tool use input provided by the LLM. This way any manual steps of defining JSON schema
for the model are avoided, which reduce a chance for errors in the process, and allows to
rapidly develop even complex data structures passed to an AI agent.
These projects are heavily dependent on [tool use](https://docs.anthropic.com/en/docs/build-with-claude/tool-use) ([function calling](https://platform.openai.com/docs/guides/function-calling)) functionality provided by many Large Language Models. Thanks to `xemantic-ai-tool-schema`, a Kotlin class, with possible additional constraints, can be automatically instantiated from the JSON tool use input provided by the LLM. This way any manual steps of defining JSON schema for the model are avoided, which reduce a chance for errors in the process, and allows to rapidly develop even complex data structures passed to an AI agent.

In short the `xemantic-ai-tool-schema` library can generate a
[JSON Schema](https://json-schema.org/) from any Kotlin class marked as `@Serializable`,
according to [kotlinx.serialization](https://kotlinlang.org/docs/serialization.html).
In short the `xemantic-ai-tool-schema` library can generate a [JSON Schema](https://json-schema.org/) from any Kotlin class marked as `@Serializable`, according to [kotlinx.serialization](https://kotlinlang.org/docs/serialization.html).

> [!TIP]
> You might be familiar with similar functionality of the
> [Pydantic](https://docs.pydantic.dev/latest/concepts/json_schema/#generating-json-schema)
> Python library, however, the standard Kotlin serialization is already fulfilling model
> metadata provisioning, so this analogy might be misleading.
> You might be familiar with similar functionality of the [Pydantic](https://docs.pydantic.dev/latest/concepts/json_schema/#generating-json-schema) Python library, however, the standard Kotlin serialization is already fulfilling model metadata provisioning, so this analogy might be misleading.
## Usage

In `build.gradle.kts` add:

```kotlin
plugins {
kotlin("multiplatform") version "2.1.0" // (or jvm for jvm-only project)
kotlin("plugin.serialization") version "2.1.0"
kotlin("multiplatform") version "2.1.0" // (or jvm for jvm-only project)
kotlin("plugin.serialization") version "2.1.0"
}

// ...
dependencies {
implementation("com.xemantic.ai:xemantic-ai-tool-schema:0.1.4")
implementation("com.xemantic.ai:xemantic-ai-tool-schema:0.1.4")
}
```

Expand All @@ -76,16 +59,16 @@ Then in your code you can define entities like this:
@Title("The full address")
@Description("An address of a person or an organization")
data class Address(
val street: String,
val city: String,
@Description("A postal code not limited to particular country")
@MinLength(3)
@MaxLength(10)
val postalCode: String,
@Pattern("[a-z]{2}")
val countryCode: String,
@Format(StringFormat.EMAIL)
val email: String? = null
val street: String,
val city: String,
@Description("A postal code not limited to particular country")
@MinLength(3)
@MaxLength(10)
val postalCode: String,
@Pattern("[a-z]{2}")
val countryCode: String,
@Format(StringFormat.EMAIL)
val email: String? = null
)
```

Expand All @@ -95,8 +78,7 @@ And when `jsonSchemaOf()` function is invoked:
val schema = jsonSchemaOf<Address>()
```

It will produce a [JsonSchema](src/commonMain/kotlin/JsonSchema.kt) instance, which
serializes to:
It will produce a [JsonSchema](src/commonMain/kotlin/JsonSchema.kt) instance, which serializes to:

```json
{
Expand Down Expand Up @@ -134,34 +116,24 @@ serializes to:
}
```

And this is the input accepted by Large Language Model APIs like
[OpenAI API](https://platform.openai.com/docs/api-reference/introduction)
and [Anthropic API](https://docs.anthropic.com/en/api/getting-started). When requesting a tool use, these LLMs
will send a JSON payload adhering to this schema, therefore
immediately deserializable as the original `@Serializable` Kotlin class.
And this is the input accepted by Large Language Model APIs like [OpenAI API](https://platform.openai.com/docs/api-reference/introduction) and [Anthropic API](https://docs.anthropic.com/en/api/getting-started).
When requesting a tool use, these LLMs will send a JSON payload adhering to this schema, therefore immediately deserializable as the original `@Serializable` Kotlin class.

More details and use cases in the [JsonSchemaGeneratorTest](src/commonTest/kotlin/generator/JsonSchemaGeneratorTest.kt).

> [!NOTE]
> When calling `toString()` function on any instance of `JsonSchema`, it will also produce a
> pretty printed `String` representation of a valid JSON schema,
> which in turn describes the Kotlin class as a serialized JSON.
> This functionality is useful for testing and debugging.
> When calling `toString()` function on any instance of `JsonSchema`, it will also produce a pretty printed `String` representation of a valid JSON schema, which in turn describes the Kotlin class as a serialized JSON. This functionality is useful for testing and debugging.
### Serializing Java `BigDecimal`s

For JVM-only projects, it is possible to specify `java.math.BigDecimal` serialization.
It will serialize decimal numbers to strings, and add `description` and `pattern`
properties to generated JSON Schema of a `BigDecimal` property.
For JVM-only projects, it is possible to specify `java.math.BigDecimal` serialization. It will serialize decimal numbers to strings, and add `description` and `pattern` properties to generated JSON Schema of a `BigDecimal` property.

See [JavaBigDecimalToSchemaTest](src/jvmTest/kotlin/serialization/JavaBigDecimalToSchemaTest.kt)
for details.
See [JavaBigDecimalToSchemaTest](src/jvmTest/kotlin/serialization/JavaBigDecimalToSchemaTest.kt) for details.

### Serializing BigDecimal/monetary values in multiplatform way

There is an interface called [Money](src/commonTest/kotlin/test/Money.kt)
defined in the tests of this project. It explains how to define and serialize monetary
amounts independently of the underlying decimal number and arithmetics provider.
There is an interface called [Money](src/commonTest/kotlin/test/Money.kt) defined in the tests of this project. It explains how to define and serialize monetary amounts independently of the underlying decimal number and arithmetics provider.
See also [xemantic-ai-money](https://github.com/xemantic/xemantic-ai-money]) project for a ready solution packaged as a library.

## Development

Expand All @@ -171,9 +143,8 @@ Clone this repo and then in the project dir:
./gradlew build
```

## Non-recommended usage
## Non-recommended usage

> [!WARNING]
> Even though this library provides basic serializable representation of a JSON Schema, it is not
> meant to fully model general purpose JSON Schema. In particular, it should not be used for deserializing
> existing schemas from JSON.
> Even though this library provides basic serializable representation of a JSON Schema, it is not meant to fully model general purpose JSON Schema.
> In particular, it should not be used for deserializing existing schemas from JSON.
6 changes: 0 additions & 6 deletions api/xemantic-ai-tool-schema.api
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ public synthetic class com/xemantic/ai/tool/schema/ArraySchema$$serializer : kot
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/xemantic/ai/tool/schema/ArraySchema;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class com/xemantic/ai/tool/schema/ArraySchema$Builder : com/xemantic/ai/tool/schema/BaseSchema$Builder {
Expand Down Expand Up @@ -73,7 +72,6 @@ public synthetic class com/xemantic/ai/tool/schema/BooleanSchema$$serializer : k
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/xemantic/ai/tool/schema/BooleanSchema;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class com/xemantic/ai/tool/schema/BooleanSchema$Builder : com/xemantic/ai/tool/schema/BaseSchema$Builder {
Expand Down Expand Up @@ -120,7 +118,6 @@ public synthetic class com/xemantic/ai/tool/schema/IntegerSchema$$serializer : k
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/xemantic/ai/tool/schema/IntegerSchema;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class com/xemantic/ai/tool/schema/IntegerSchema$Builder : com/xemantic/ai/tool/schema/NumericSchema$Builder {
Expand Down Expand Up @@ -180,7 +177,6 @@ public synthetic class com/xemantic/ai/tool/schema/NumberSchema$$serializer : ko
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/xemantic/ai/tool/schema/NumberSchema;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class com/xemantic/ai/tool/schema/NumberSchema$Builder : com/xemantic/ai/tool/schema/NumericSchema$Builder {
Expand Down Expand Up @@ -233,7 +229,6 @@ public synthetic class com/xemantic/ai/tool/schema/ObjectSchema$$serializer : ko
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/xemantic/ai/tool/schema/ObjectSchema;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class com/xemantic/ai/tool/schema/ObjectSchema$Builder : com/xemantic/ai/tool/schema/BaseSchema$Builder {
Expand Down Expand Up @@ -312,7 +307,6 @@ public synthetic class com/xemantic/ai/tool/schema/StringSchema$$serializer : ko
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/xemantic/ai/tool/schema/StringSchema;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class com/xemantic/ai/tool/schema/StringSchema$Builder : com/xemantic/ai/tool/schema/BaseSchema$Builder {
Expand Down
Loading

0 comments on commit 78d707c

Please sign in to comment.