Skip to content
Closed
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
2 changes: 2 additions & 0 deletions crates/openshell-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ enum CliProviderType {
Generic,
Openai,
Anthropic,
BitdeerAi,
Nvidia,
Gitlab,
Github,
Expand Down Expand Up @@ -610,6 +611,7 @@ impl CliProviderType {
Self::Generic => "generic",
Self::Openai => "openai",
Self::Anthropic => "anthropic",
Self::BitdeerAi => "bitdeer-ai",
Self::Nvidia => "nvidia",
Self::Gitlab => "gitlab",
Self::Github => "github",
Expand Down
25 changes: 25 additions & 0 deletions crates/openshell-core/src/inference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ static NVIDIA_PROFILE: InferenceProviderProfile = InferenceProviderProfile {
default_headers: &[],
};

static BITDEER_AI_PROFILE: InferenceProviderProfile = InferenceProviderProfile {
provider_type: "bitdeer-ai",
default_base_url: "https://api-inference.bitdeer.ai/v1",
protocols: OPENAI_PROTOCOLS,
credential_key_names: &["BITDEERAI_API_KEY"],
base_url_config_keys: &["BITDEERAI_BASE_URL"],
auth: AuthHeader::Bearer,
default_headers: &[],
};

/// Look up the inference provider profile for a given provider type.
///
/// Returns `None` for provider types that don't support inference routing
Expand All @@ -95,6 +105,7 @@ pub fn profile_for(provider_type: &str) -> Option<&'static InferenceProviderProf
"openai" => Some(&OPENAI_PROFILE),
"anthropic" => Some(&ANTHROPIC_PROFILE),
"nvidia" => Some(&NVIDIA_PROFILE),
"bitdeer-ai" => Some(&BITDEER_AI_PROFILE),
_ => None,
}
}
Expand Down Expand Up @@ -176,6 +187,7 @@ mod tests {
assert!(profile_for("openai").is_some());
assert!(profile_for("anthropic").is_some());
assert!(profile_for("nvidia").is_some());
assert!(profile_for("bitdeer-ai").is_some());
assert!(profile_for("OpenAI").is_some()); // case insensitive
}

Expand Down Expand Up @@ -206,4 +218,17 @@ mod tests {
assert_eq!(auth, AuthHeader::Bearer);
assert!(headers.is_empty());
}

#[test]
fn bitdeer_ai_profile_has_correct_defaults() {
let profile = profile_for("bitdeer-ai").expect("bitdeer-ai profile should exist");
assert_eq!(profile.provider_type, "bitdeer-ai");
assert_eq!(
profile.default_base_url,
"https://api-inference.bitdeer.ai/v1"
);
assert_eq!(profile.credential_key_names, &["BITDEERAI_API_KEY"]);
assert_eq!(profile.auth, AuthHeader::Bearer);
assert!(profile.default_headers.is_empty());
}
}
4 changes: 4 additions & 0 deletions crates/openshell-providers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ impl ProviderRegistry {
registry.register(providers::generic::GenericProvider);
registry.register(providers::openai::OpenaiProvider);
registry.register(providers::anthropic::AnthropicProvider);
registry.register(providers::bitdeer_ai::BitdeerAiProvider);
registry.register(providers::nvidia::NvidiaProvider);
registry.register(providers::gitlab::GitlabProvider);
registry.register(providers::github::GithubProvider);
Expand Down Expand Up @@ -132,6 +133,7 @@ pub fn normalize_provider_type(input: &str) -> Option<&'static str> {
"generic" => Some("generic"),
"openai" => Some("openai"),
"anthropic" => Some("anthropic"),
"bitdeer-ai" | "bitdeer" => Some("bitdeer-ai"),
"nvidia" => Some("nvidia"),
"gitlab" | "glab" => Some("gitlab"),
"github" | "gh" => Some("github"),
Expand Down Expand Up @@ -164,6 +166,8 @@ mod tests {
assert_eq!(normalize_provider_type("openai"), Some("openai"));
assert_eq!(normalize_provider_type("anthropic"), Some("anthropic"));
assert_eq!(normalize_provider_type("nvidia"), Some("nvidia"));
assert_eq!(normalize_provider_type("bitdeer-ai"), Some("bitdeer-ai"));
assert_eq!(normalize_provider_type("bitdeer"), Some("bitdeer-ai"));
assert_eq!(normalize_provider_type("unknown"), None);
}

Expand Down
46 changes: 46 additions & 0 deletions crates/openshell-providers/src/providers/bitdeer_ai.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

use crate::{
ProviderDiscoverySpec, ProviderError, ProviderPlugin, RealDiscoveryContext, discover_with_spec,
};

pub struct BitdeerAiProvider;

pub const SPEC: ProviderDiscoverySpec = ProviderDiscoverySpec {
id: "bitdeer-ai",
credential_env_vars: &["BITDEERAI_API_KEY"],
};

impl ProviderPlugin for BitdeerAiProvider {
fn id(&self) -> &'static str {
SPEC.id
}

fn discover_existing(&self) -> Result<Option<crate::DiscoveredProvider>, ProviderError> {
discover_with_spec(&SPEC, &RealDiscoveryContext)
}

fn credential_env_vars(&self) -> &'static [&'static str] {
SPEC.credential_env_vars
}
}

#[cfg(test)]
mod tests {
use super::SPEC;
use crate::discover_with_spec;
use crate::test_helpers::MockDiscoveryContext;

#[test]
fn discovers_bitdeer_ai_env_credentials() {
let ctx = MockDiscoveryContext::new().with_env("BITDEERAI_API_KEY", "bd-test-key-123");
let discovered = discover_with_spec(&SPEC, &ctx)
.expect("discovery")
.expect("provider");
assert_eq!(
discovered.credentials.get("BITDEERAI_API_KEY"),
Some(&"bd-test-key-123".to_string())
);
}
}
1 change: 1 addition & 0 deletions crates/openshell-providers/src/providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

pub mod anthropic;
pub mod bitdeer_ai;
pub mod claude;
pub mod codex;
pub mod generic;
Expand Down
1 change: 1 addition & 0 deletions docs/sandboxes/manage-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ The following provider types are supported.
| `github` | `GITHUB_TOKEN`, `GH_TOKEN` | GitHub API, `gh` CLI — refer to {doc}`/tutorials/github-sandbox` |
| `gitlab` | `GITLAB_TOKEN`, `GLAB_TOKEN`, `CI_JOB_TOKEN` | GitLab API, `glab` CLI |
| `nvidia` | `NVIDIA_API_KEY` | NVIDIA API Catalog |
| `bitdeer-ai` | `BITDEERAI_API_KEY` | Bitdeer AI inference API |
| `generic` | User-defined | Any service with custom credentials |

:::{tip}
Expand Down
Loading