Skip to content
Merged
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
465 changes: 426 additions & 39 deletions crates/connector-hub/src/main.rs

Large diffs are not rendered by default.

142 changes: 142 additions & 0 deletions crates/hub-auth/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,148 @@ impl AuthStore {
}
}

// Linode
if let Ok(token) = std::env::var("LINODE_API_TOKEN") {
store.add(Credential {
provider: "linode".into(),
account_id: "default".into(),
base_url: Some("https://api.linode.com/v4".into()),
auth: AuthMethod::Bearer { token },
});
}

// Kimi (Moonshot)
if let Ok(key) =
std::env::var("MOONSHOT_API_KEY").or_else(|_| std::env::var("KIMI_API_KEY"))
{
let base = std::env::var("MOONSHOT_BASE_URL")
.unwrap_or_else(|_| "https://api.moonshot.cn/v1".into());
store.add(Credential {
provider: "kimi".into(),
account_id: "default".into(),
base_url: Some(base),
auth: AuthMethod::Bearer { token: key },
});
}

// Cloudflare AI
if let (Ok(token), Ok(account_id)) = (
std::env::var("CLOUDFLARE_API_TOKEN"),
std::env::var("CLOUDFLARE_ACCOUNT_ID"),
) {
store.add(Credential {
provider: "cloudflare".into(),
account_id: "default".into(),
base_url: Some(format!(
"https://api.cloudflare.com/client/v4/accounts/{account_id}"
)),
auth: AuthMethod::Bearer { token },
});
}

// OneProvider
if let Ok(key) = std::env::var("ONEPROVIDER_API_KEY") {
store.add(Credential {
provider: "oneprovider".into(),
account_id: "default".into(),
base_url: Some("https://api.oneprovider.com".into()),
auth: AuthMethod::Bearer { token: key },
});
}

// Tawk.to
if let Ok(key) = std::env::var("TAWK_API_KEY") {
store.add(Credential {
provider: "tawk".into(),
account_id: "default".into(),
base_url: Some("https://api.tawk.to/v1".into()),
auth: AuthMethod::Bearer { token: key },
});
}

// WHM
if let (Ok(host), Ok(user), Ok(token)) = (
std::env::var("WHM_HOST"),
std::env::var("WHM_USER"),
std::env::var("WHM_API_TOKEN"),
) {
store.add(Credential {
provider: "whm".into(),
account_id: "default".into(),
base_url: Some(format!("https://{host}:2087")),
auth: AuthMethod::Header {
name: "Authorization".into(),
value: format!("whm {user}:{token}"),
},
});
}

// cPanel
if let (Ok(host), Ok(user), Ok(token)) = (
std::env::var("CPANEL_HOST"),
std::env::var("CPANEL_USER"),
std::env::var("CPANEL_API_TOKEN"),
) {
store.add(Credential {
provider: "cpanel".into(),
account_id: "default".into(),
base_url: Some(format!("https://{host}:2083")),
auth: AuthMethod::Header {
name: "Authorization".into(),
value: format!("cpanel {user}:{token}"),
},
});
}

// WHMCS
if let (Ok(url), Ok(identifier), Ok(secret)) = (
std::env::var("WHMCS_URL"),
std::env::var("WHMCS_API_IDENTIFIER"),
std::env::var("WHMCS_API_SECRET"),
) {
store.add(Credential {
provider: "whmcs".into(),
account_id: "default".into(),
base_url: Some(format!("{}/includes/api.php", url.trim_end_matches('/'))),
auth: AuthMethod::Basic {
username: identifier,
password: secret,
},
});
}

// UltaHost (WHMCS billing)
if let (Ok(url), Ok(user), Ok(key)) = (
std::env::var("ULTRAHOST_WHMCS_URL"),
std::env::var("ULTRAHOST_API_USER"),
std::env::var("ULTRAHOST_API_KEY"),
) {
store.add(Credential {
provider: "ultrahost".into(),
account_id: "default".into(),
base_url: Some(url),
auth: AuthMethod::Basic {
username: user,
password: key,
},
});
}

// Claude/Anthropic auth is already registered above under "anthropic".
// The spec file is named "claude.json" so the provider is "claude".
// We need a mapping from "claude" to the anthropic credentials.
if let Ok(key) = std::env::var("ANTHROPIC_API_KEY") {
store.add(Credential {
provider: "claude".into(),
account_id: "default".into(),
base_url: Some("https://api.anthropic.com/v1".into()),
auth: AuthMethod::Header {
name: "x-api-key".into(),
value: key,
},
});
}

// Contabo password grant
if let (Ok(client_id), Ok(client_secret), Ok(username), Ok(password)) = (
std::env::var("CONTABO_CLIENT_ID"),
Expand Down
6 changes: 6 additions & 0 deletions crates/hub-core/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ impl Dispatcher {
Transport::Smtp => {
return self.execute_smtp(auth, account, args).await;
}
Transport::Local => {
return Ok(ExecutionOutcome::ConfigurationRequired {
provider: op.provider.clone(),
missing: vec![format!("local runtime required for operation {}", op.id)],
});
}
Transport::Http => {}
}

Expand Down
1 change: 1 addition & 0 deletions crates/hub-core/src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub enum Transport {
#[default]
Http,
Smtp,
Local,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down
65 changes: 65 additions & 0 deletions specs/claude.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"openapi": "3.0.3",
"info": {
"title": "Claude API",
"version": "1.0.0"
},
"servers": [
{ "url": "https://api.anthropic.com/v1" }
],
"security": [
{ "ApiKeyAuth": [] }
],
"components": {
"securitySchemes": {
"ApiKeyAuth": {
"type": "apiKey",
"in": "header",
"name": "x-api-key"
}
}
},
"paths": {
"/messages": {
"post": {
"operationId": "chat",
"summary": "Create a message",
"tags": ["llm", "chat"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["messages"],
"properties": {
"messages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"role": { "type": "string" },
"content": { "type": "string" }
}
}
},
"model": { "type": "string" },
"system": { "type": "string" },
"max_tokens": { "type": "integer", "default": 1024 },
"temperature": { "type": "number" }
}
}
}
}
}
}
},
"/models": {
"get": {
"operationId": "list_models",
"summary": "List available models",
"tags": ["llm", "models"]
}
}
}
}
90 changes: 90 additions & 0 deletions specs/cloudflare.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"openapi": "3.0.3",
"info": {
"title": "Cloudflare Workers AI API",
"version": "1.0.0"
},
"servers": [
{ "url": "https://api.cloudflare.com/client/v4" }
],
"security": [
{ "BearerAuth": [] }
],
"components": {
"securitySchemes": {
"BearerAuth": {
"type": "http",
"scheme": "bearer"
}
}
},
"paths": {
"/accounts/{account_id}/ai/run/{model}": {
"post": {
"operationId": "chat",
"summary": "Run a chat completion on Workers AI",
"tags": ["llm", "chat"],
"parameters": [
{ "name": "account_id", "in": "path", "required": true, "schema": { "type": "string" } },
{ "name": "model", "in": "path", "required": true, "schema": { "type": "string", "default": "@cf/meta/llama-3.1-8b-instruct" } }
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["messages"],
"properties": {
"messages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"role": { "type": "string" },
"content": { "type": "string" }
}
}
},
"max_tokens": { "type": "integer" },
"temperature": { "type": "number" },
"stream": { "type": "boolean" }
}
}
}
}
}
}
},
"/accounts/{account_id}/ai/run": {
"post": {
"operationId": "run_model",
"summary": "Run an arbitrary AI model",
"tags": ["llm", "inference"],
"parameters": [
{ "name": "account_id", "in": "path", "required": true, "schema": { "type": "string" } }
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["model", "input"],
"properties": {
"model": { "type": "string" },
"input": {
"oneOf": [
{ "type": "object" },
{ "type": "string" }
]
}
}
}
}
}
}
}
}
}
}
Loading
Loading