Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2024-2026 Embabel Pty Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.embabel.agent.api.models

/**
* Provides constants for Atlas Cloud model identifiers.
* Atlas Cloud exposes models from multiple vendors through an OpenAI-compatible API.
*
* @see <a href="https://www.atlascloud.ai/models">Atlas Cloud Models</a>
*/
class AtlasCloudModels {

companion object {

const val QWEN3_5_FLASH = "qwen/qwen3.5-flash"
const val QWEN3_8_MAX = "qwen/qwen3.8-max"

const val PROVIDER = "Atlas Cloud"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import java.util.concurrent.Executors
* OpenAiCompatibleModelFactory.deepSeek(userKey),
* OpenAiCompatibleModelFactory.mistral(userKey),
* OpenAiCompatibleModelFactory.gemini(userKey),
* OpenAiCompatibleModelFactory.atlasCloud(userKey),
* )
* val detectedProvider = service.provider
* ```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ val service: LlmService<*> = OpenAiCompatibleModelFactory.mistral(userKey).build

// Gemini (OpenAI-compatible endpoint)
val service: LlmService<*> = OpenAiCompatibleModelFactory.gemini(userKey).buildValidated()

// Atlas Cloud (OpenAI-compatible endpoint)
val service: LlmService<*> = OpenAiCompatibleModelFactory.atlasCloud(userKey).buildValidated()
----

`buildValidated()` makes a single probe call with no retries.
Expand Down Expand Up @@ -258,6 +261,7 @@ val service: LlmService<*> = detectProvider(
OpenAiCompatibleModelFactory.deepSeek(userKey),
OpenAiCompatibleModelFactory.mistral(userKey),
OpenAiCompatibleModelFactory.gemini(userKey),
OpenAiCompatibleModelFactory.atlasCloud(userKey),
)
val detectedProvider: String = service.provider
----
Expand Down Expand Up @@ -543,4 +547,3 @@ Remove the `embabel.agent.logging.personality` key to disable personality-based

As all logging results from listening to events via an `AgenticEventListener`, you can also easily create your own customized logging.


Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.embabel.agent.openai

import com.embabel.agent.api.models.AtlasCloudModels
import com.embabel.agent.api.models.DeepSeekModels
import com.embabel.agent.api.models.GoogleGenAiModels
import com.embabel.agent.api.models.MistralAiModels
Expand Down Expand Up @@ -127,6 +128,18 @@ open class OpenAiCompatibleModelFactory(
GoogleGenAiModels.PROVIDER,
)

/**
* Returns a [ByokSpec] for Atlas Cloud (OpenAI-compatible endpoint).
* Validates against [AtlasCloudModels.QWEN3_5_FLASH] by default.
*/
fun atlasCloud(apiKey: String): ByokSpec =
ByokSpec(
"https://api.atlascloud.ai/v1",
apiKey,
AtlasCloudModels.QWEN3_5_FLASH,
AtlasCloudModels.PROVIDER,
)

/**
* Returns a [ByokSpec] for a custom OpenAI-compatible provider.
*
Expand Down Expand Up @@ -191,8 +204,9 @@ open class OpenAiCompatibleModelFactory(
* so it can be passed directly to [com.embabel.common.byok.detectProvider].
*
* Obtained via the companion factory methods ([openAi], [deepSeek], [mistral], [gemini],
* or [byok] for custom providers). Use [validating] to override the default validation
* model and provider — for example if the key only grants access to a specific model tier.
* [atlasCloud], or [byok] for custom providers). Use [validating] to override the default
* validation model and provider — for example if the key only grants access to a specific
* model tier.
*/
class ByokSpec internal constructor(
private val baseUrl: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class OpenAiCompatibleModelFactoryBuildValidatedTest {
OpenAiCompatibleModelFactory.deepSeek(""),
OpenAiCompatibleModelFactory.mistral("\t"),
OpenAiCompatibleModelFactory.gemini(" "),
OpenAiCompatibleModelFactory.atlasCloud("\n"),
).forEach { spec ->
val e = assertThrows<InvalidApiKeyException> { spec.buildValidated() }
assertEquals(BLANK_API_KEY_MESSAGE, e.message)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ class OpenAiCompatibleModelFactoryByokIT {
assertNotNull(service)
}

@Test
@EnabledIfEnvironmentVariable(named = "ATLASCLOUD_API_KEY", matches = ".+")
fun `atlasCloud buildValidated succeeds with valid key`() {
val service = OpenAiCompatibleModelFactory.atlasCloud(System.getenv("ATLASCLOUD_API_KEY"))
.buildValidated()
assertNotNull(service)
assertEquals("Atlas Cloud", service.provider)
}

@Test
@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+")
fun `openAiEmbedding buildValidated succeeds with valid key`() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.embabel.agent.openai

import com.embabel.agent.api.models.AtlasCloudModels
import com.embabel.agent.api.models.DeepSeekModels
import com.embabel.agent.api.models.GoogleGenAiModels
import com.embabel.agent.api.models.MistralAiModels
Expand Down Expand Up @@ -45,6 +46,11 @@ class OpenAiCompatibleModelFactoryByokSpecTest {
assertInstanceOf(ByokFactory::class.java, OpenAiCompatibleModelFactory.gemini("key"))
}

@Test
fun `atlasCloud returns ByokFactory`() {
assertInstanceOf(ByokFactory::class.java, OpenAiCompatibleModelFactory.atlasCloud("key"))
}

@Test
fun `byok with explicit params returns ByokFactory`() {
assertInstanceOf(
Expand Down Expand Up @@ -74,11 +80,16 @@ class OpenAiCompatibleModelFactoryByokSpecTest {
val deepSeekSpec = OpenAiCompatibleModelFactory.deepSeek("key")
val mistralSpec = OpenAiCompatibleModelFactory.mistral("key")
val geminiSpec = OpenAiCompatibleModelFactory.gemini("key")
val atlasCloudSpec = OpenAiCompatibleModelFactory.atlasCloud("key")

// Each spec should construct without error (no network call at this stage)
assertInstanceOf(ByokFactory::class.java, openAiSpec)
assertInstanceOf(ByokFactory::class.java, deepSeekSpec)
assertInstanceOf(ByokFactory::class.java, mistralSpec)
assertInstanceOf(ByokFactory::class.java, geminiSpec)
assertInstanceOf(ByokFactory::class.java, atlasCloudSpec)

val overridden = atlasCloudSpec.validating(AtlasCloudModels.QWEN3_8_MAX, AtlasCloudModels.PROVIDER)
assertInstanceOf(ByokFactory::class.java, overridden)
}
}