Skip to content

Commit a33ba61

Browse files
authored
Merge pull request #2 from tddworks/kotlin-2.2.0
update kotlin to 2.2.0
2 parents 02e2624 + da12041 commit a33ba61

File tree

13 files changed

+166
-37
lines changed

13 files changed

+166
-37
lines changed

.github/workflows/main.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ on:
44
workflow_dispatch: # Start a workflow
55
push:
66
branches:
7-
- "main"
7+
- main
8+
pull_request:
9+
branches:
10+
- main
811

912
jobs:
1013
build:

CLAUDE.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Build and Development Commands
6+
7+
### Building the Project
8+
```bash
9+
./gradlew build # Build all modules
10+
./gradlew clean build # Clean and build all modules
11+
./gradlew assemble # Assemble outputs without running tests
12+
```
13+
14+
### Running Tests
15+
```bash
16+
./gradlew test # Run tests for all platforms
17+
./gradlew jvmTest # Run JVM tests only
18+
./gradlew macosArm64Test # Run macOS ARM64 tests
19+
./gradlew iosSimulatorArm64Test # Run iOS simulator tests
20+
./gradlew allTests # Run tests for all targets with aggregated report
21+
./gradlew check # Run all verification tasks
22+
```
23+
24+
### Test Coverage
25+
```bash
26+
./gradlew koverHtmlReport # Generate HTML coverage report for all code
27+
./gradlew koverXmlReport # Generate XML coverage report
28+
./gradlew koverVerify # Run coverage verification (min 86% required)
29+
```
30+
31+
### Running Specific Module Tests
32+
```bash
33+
./gradlew :openai-client:openai-client-core:test
34+
./gradlew :anthropic-client:anthropic-client-core:test
35+
./gradlew :ollama-client:ollama-client-core:test
36+
./gradlew :gemini-client:gemini-client-core:test
37+
./gradlew :openai-gateway:openai-gateway-core:test
38+
```
39+
40+
## Project Architecture
41+
42+
This is a Kotlin Multiplatform project providing AI/LLM client implementations for multiple providers. The codebase follows a modular architecture with clear separation of concerns.
43+
44+
### Core Architecture Patterns
45+
46+
1. **Multiplatform Structure**: Each client module has platform-specific implementations:
47+
- `-core`: Common implementation shared across platforms
48+
- `-darwin`: Apple platform specific implementations (iOS, macOS)
49+
- `-cio`: JVM-specific implementations using CIO
50+
51+
2. **Provider Pattern**: The `openai-gateway` module implements a gateway pattern that allows switching between different LLM providers (OpenAI, Anthropic, Ollama, Gemini) using a unified interface.
52+
53+
3. **HTTP Client Abstraction**: The `common` module provides a shared `HttpRequester` interface that abstracts HTTP operations across platforms, using Ktor under the hood.
54+
55+
4. **Dependency Injection**: Uses Koin for dependency injection across the codebase, with platform-specific configurations.
56+
57+
### Module Structure
58+
59+
- **common/**: Shared networking and utility code
60+
- HTTP client abstraction (`HttpRequester`)
61+
- Ktor configuration for different platforms
62+
- JSON serialization utilities
63+
64+
- **openai-client/**: OpenAI API client implementation
65+
- Chat completions, images, and legacy completions APIs
66+
- Streaming support for chat completions
67+
68+
- **anthropic-client/**: Anthropic Claude API client
69+
- Messages API implementation
70+
- Image support with base64 encoding
71+
72+
- **ollama-client/**: Ollama local LLM client
73+
- Chat and generate endpoints
74+
- Local model management
75+
76+
- **gemini-client/**: Google Gemini API client
77+
- Text generation with multimodal support
78+
79+
- **openai-gateway/**: Unified gateway for all providers
80+
- Provider abstraction allowing runtime switching
81+
- Adapter pattern to convert between provider-specific and OpenAI formats
82+
- Extensions for converting requests/responses between different provider formats
83+
84+
### Key Interfaces
85+
86+
- `OpenAI`: Main interface for OpenAI operations (Chat, Images, Completions)
87+
- `OpenAIGateway`: Gateway interface for multi-provider support
88+
- `HttpRequester`: HTTP client abstraction for cross-platform requests
89+
- `OpenAIProvider`: Provider interface for different LLM services
90+
91+
### Configuration
92+
93+
Each client uses a configuration pattern (e.g., `OpenAIConfig`, `AnthropicConfig`) that requires:
94+
- Base URL (with defaults for each provider)
95+
- API key
96+
- Optional provider-specific settings
97+
98+
### Testing Strategy
99+
100+
The project uses:
101+
- Unit tests with mocked HTTP clients (`MockHttpClient`)
102+
- Integration tests (files ending with `ITest`) for actual API calls
103+
- Platform-specific test configurations
104+
- Kover for code coverage with 86% minimum threshold

anthropic-client/anthropic-client-core/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ kotlin {
3636
implementation(libs.koin.test)
3737
implementation(libs.koin.test.junit5)
3838
implementation(libs.app.cash.turbine)
39-
implementation("com.tngtech.archunit:archunit-junit5:1.1.0")
39+
implementation("com.tngtech.archunit:archunit-junit5:1.4.1")
4040
implementation("org.reflections:reflections:0.10.2")
4141
implementation(libs.org.skyscreamer.jsonassert)
42+
implementation("org.junit.platform:junit-platform-launcher")
4243
}
4344
}
4445
}

build.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import nl.littlerobots.vcu.plugin.resolver.VersionSelectors
2+
13
plugins {
24
`maven-publish`
35
//trick: for the same plugin versions in all sub-modules
@@ -8,6 +10,7 @@ plugins {
810
alias(libs.plugins.build.dokka.plugin)
911

1012
alias(libs.plugins.kotlinx.binary.validator) apply false
13+
id("nl.littlerobots.version-catalog-update") version "1.0.0"
1114
id("com.tddworks.central-portal-publisher") version "0.0.5"
1215
}
1316

@@ -28,6 +31,10 @@ dependencies {
2831
kover(projects.common)
2932
}
3033

34+
versionCatalogUpdate {
35+
versionSelector(VersionSelectors.STABLE)
36+
}
37+
3138
val autoVersion = project.property(
3239
if (project.hasProperty("AUTO_VERSION")) {
3340
"AUTO_VERSION"

common/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ plugins {
77
kotlin {
88
jvm()
99
macosArm64()
10+
macosX64()
1011
iosArm64()
1112
iosSimulatorArm64()
1213

@@ -40,8 +41,9 @@ kotlin {
4041
implementation(libs.koin.test)
4142
implementation(libs.koin.test.junit5)
4243
implementation(libs.app.cash.turbine)
43-
implementation("com.tngtech.archunit:archunit-junit5:1.1.0")
44+
implementation("com.tngtech.archunit:archunit-junit5:1.4.1")
4445
implementation("org.reflections:reflections:0.10.2")
46+
implementation("org.junit.platform:junit-platform-launcher")
4547
}
4648
}
4749
}

gemini-client/gemini-client-core/build.gradle.kts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import com.google.devtools.ksp.gradle.KspAATask
12
import com.google.devtools.ksp.gradle.KspTaskMetadata
23
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
4+
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
35

46
plugins {
57
alias(libs.plugins.kotlinx.serialization)
@@ -46,9 +48,10 @@ kotlin {
4648
implementation(libs.koin.test)
4749
implementation(libs.koin.test.junit5)
4850
implementation(libs.app.cash.turbine)
49-
implementation("com.tngtech.archunit:archunit-junit5:1.1.0")
51+
implementation("com.tngtech.archunit:archunit-junit5:1.4.1")
5052
implementation("org.reflections:reflections:0.10.2")
5153
implementation(libs.org.skyscreamer.jsonassert)
54+
implementation("org.junit.platform:junit-platform-launcher")
5255
}
5356
}
5457
}
@@ -59,12 +62,22 @@ dependencies {
5962
}
6063

6164
// WORKAROUND: ADD this dependsOn("kspCommonMainKotlinMetadata") instead of above dependencies
62-
tasks.withType<KotlinCompile>().configureEach {
65+
//tasks.withType<KotlinCompile>().configureEach {
66+
// if (name != "kspCommonMainKotlinMetadata") {
67+
// dependsOn("kspCommonMainKotlinMetadata")
68+
// }
69+
//}
70+
71+
// Add dependency for native compilation tasks as well
72+
tasks.withType<KspAATask>().configureEach {
6373
if (name != "kspCommonMainKotlinMetadata") {
6474
dependsOn("kspCommonMainKotlinMetadata")
6575
}
6676
}
67-
77+
// `tasks.sourcesJar` is not exists, so `tasks.metadataSourcesJar`
78+
tasks.sourcesJar.configure {
79+
dependsOn("kspCommonMainKotlinMetadata")
80+
}
6881

6982
ksp {
7083
arg("KOIN_DEFAULT_MODULE", "false")

gradle.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ kotlin.mpp.enableCInteropCommonization=true
1111
android.useAndroidX=true
1212
android.nonTransitiveRClass=true
1313

14+
org.jetbrains.dokka.experimental.gradle.pluginMode=V2EnabledWithHelpers
15+
1416
#publishing for kmmbridge
1517
## Darwin Publish require from - nextVersion parameter must be a valid semver string. Current value: 0.1.4.
1618
## So we need set version to 0.1 or 0.2 ......

gradle/libs.versions.toml

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ jvm-test = ["juinit-jupiter", "mockito-junit-jupiter", "mockito-kotlin", "ktor-c
1010
#kotlin-gradle-plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
1111
ksp = { id ="com.google.devtools.ksp", version.ref = "ksp" }
1212

13-
1413
androidLibrary = { id = "com.android.library", version.ref = "agp" }
1514
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
1615
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
@@ -20,13 +19,7 @@ touchlab-skie = { id = "co.touchlab.skie", version.ref = "touchlab-skie" }
2019

2120
com-linecorp-build-recipe = { id = "com.linecorp.build-recipe-plugin", version.ref = "com-linecorp-build-recipe-plugin" }
2221

23-
kotlinx-binary-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version = "0.14.0" }
24-
## ⬆ = "0.15.0" }
25-
## ⬆ = "0.15.1" }
26-
## ⬆ = "0.16.0" }
27-
## ⬆ = "0.16.1" }
28-
## ⬆ = "0.16.2" }
29-
## ⬆ = "0.16.3" }
22+
kotlinx-binary-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version = "0.18.1" }
3023

3124
# Quality and coverage
3225
kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
@@ -41,42 +34,42 @@ gradle-kotlinter = { id = "org.jmailen.kotlinter", version.ref = "gradle-kotlint
4134

4235
[versions]
4336

44-
agp = "8.7.0"
45-
kotlin = "2.0.20"
37+
agp = "8.12.1"
38+
kotlin = "2.2.0"
4639

47-
ktor = "2.3.12"
48-
kotlinx-serialization = "1.7.3"
49-
kover = "0.8.3"
50-
kotlinx-coroutines = "1.9.0"
40+
ktor = "3.2.3"
41+
kotlinx-serialization = "1.9.0"
42+
kover = "0.9.1"
43+
kotlinx-coroutines = "1.10.2"
5144

5245
#logging-versions
5346
napier = "2.6.1"
5447

5548
#test-versions
56-
junit = "5.11.2"
57-
mockito-junit-jupiter = "5.14.1"
58-
mockito-kotlin = "5.4.0"
59-
assertj-core = "3.26.3"
49+
junit = "5.11.3"
50+
mockito-junit-jupiter = "5.19.0"
51+
mockito-kotlin = "6.0.0"
52+
assertj-core = "3.27.4"
6053
app-cash-turbine = "1.0.0"
6154
org-skyscreamer-jsonassert = "2.0-rc1"
6255

6356
#formatting-versions
64-
gradle-kotlinter = "4.2.0"
57+
gradle-kotlinter = "5.2.0"
6558

6659
# DI
67-
koin-core = "4.0.1"
68-
koin-annotations = "2.0.0-Beta3"
60+
koin-core = "4.1.0"
61+
koin-annotations = "2.1.0"
6962

7063
# plugins
71-
touchlab-skie = "0.9.2"
64+
touchlab-skie = "0.10.5"
7265

73-
touchlab-kmmbridge = "1.2.0"
66+
touchlab-kmmbridge = "1.2.1"
7467

7568
com-linecorp-build-recipe-plugin = "1.1.1"
7669

77-
dokka = "1.9.20"
70+
dokka = "2.0.0"
7871

79-
ksp = "2.0.20-1.0.25"
72+
ksp = "2.2.0-2.0.2"
8073

8174
android-minSdk = "24"
8275
android-compileSdk = "34"
@@ -125,8 +118,7 @@ kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-t
125118

126119
org-skyscreamer-jsonassert = { module = "org.skyscreamer:jsonassert", version.ref = "org-skyscreamer-jsonassert" }
127120

128-
app-cash-turbine = { module = "app.cash.turbine:turbine", version = "1.0.0" }
129-
## ⬆ = "1.1.0" }
121+
app-cash-turbine = { module = "app.cash.turbine:turbine", version = "1.2.1" }
130122

131123
# Formatting
132124
gradle-kotlinter = { module = "org.jmailen.gradle:kotlinter-gradle", version.ref = "gradle-kotlinter" }

ollama-client/ollama-client-core/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ kotlin {
3636
implementation(libs.koin.test)
3737
implementation(libs.koin.test.junit5)
3838
implementation(libs.app.cash.turbine)
39-
implementation("com.tngtech.archunit:archunit-junit5:1.1.0")
39+
implementation("com.tngtech.archunit:archunit-junit5:1.4.1")
4040
implementation("org.reflections:reflections:0.10.2")
41+
implementation("org.junit.platform:junit-platform-launcher")
4142
}
4243
}
4344
}

openai-client/openai-client-core/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ plugins {
77
kotlin {
88
jvm()
99
macosArm64()
10+
macosX64()
1011
iosArm64()
1112
iosSimulatorArm64()
1213
sourceSets {
@@ -34,8 +35,9 @@ kotlin {
3435
implementation(libs.koin.test)
3536
implementation(libs.koin.test.junit5)
3637
implementation(libs.app.cash.turbine)
37-
implementation("com.tngtech.archunit:archunit-junit5:1.1.0")
38+
implementation("com.tngtech.archunit:archunit-junit5:1.4.1")
3839
implementation("org.reflections:reflections:0.10.2")
40+
implementation("org.junit.platform:junit-platform-launcher")
3941
}
4042
}
4143
}

0 commit comments

Comments
 (0)