diff --git a/Cargo.lock b/Cargo.lock
index 042eae08..080778b7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3866,7 +3866,7 @@ dependencies = [
[[package]]
name = "openfang-api"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"async-trait",
"axum",
@@ -3902,7 +3902,7 @@ dependencies = [
[[package]]
name = "openfang-channels"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"async-trait",
"axum",
@@ -3933,7 +3933,7 @@ dependencies = [
[[package]]
name = "openfang-cli"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"clap",
"clap_complete",
@@ -3960,7 +3960,7 @@ dependencies = [
[[package]]
name = "openfang-desktop"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"axum",
"open",
@@ -3986,7 +3986,7 @@ dependencies = [
[[package]]
name = "openfang-extensions"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"aes-gcm",
"argon2",
@@ -4014,7 +4014,7 @@ dependencies = [
[[package]]
name = "openfang-hands"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"chrono",
"dashmap",
@@ -4031,7 +4031,7 @@ dependencies = [
[[package]]
name = "openfang-kernel"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"async-trait",
"chrono",
@@ -4067,7 +4067,7 @@ dependencies = [
[[package]]
name = "openfang-memory"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"async-trait",
"chrono",
@@ -4086,7 +4086,7 @@ dependencies = [
[[package]]
name = "openfang-migrate"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"chrono",
"dirs 6.0.0",
@@ -4105,7 +4105,7 @@ dependencies = [
[[package]]
name = "openfang-runtime"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"anyhow",
"async-trait",
@@ -4137,7 +4137,7 @@ dependencies = [
[[package]]
name = "openfang-skills"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"chrono",
"hex",
@@ -4160,7 +4160,7 @@ dependencies = [
[[package]]
name = "openfang-types"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"async-trait",
"chrono",
@@ -4179,7 +4179,7 @@ dependencies = [
[[package]]
name = "openfang-wire"
-version = "0.3.14"
+version = "0.3.15"
dependencies = [
"async-trait",
"chrono",
@@ -8791,7 +8791,7 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
[[package]]
name = "xtask"
-version = "0.3.14"
+version = "0.3.15"
[[package]]
name = "yoke"
diff --git a/Cargo.toml b/Cargo.toml
index 49950086..c3b7f33e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,7 +18,7 @@ members = [
]
[workspace.package]
-version = "0.3.15"
+version = "0.3.16"
edition = "2021"
license = "Apache-2.0 OR MIT"
repository = "https://github.com/RightNow-AI/openfang"
diff --git a/crates/openfang-api/src/middleware.rs b/crates/openfang-api/src/middleware.rs
index b9bad51b..b2785da9 100644
--- a/crates/openfang-api/src/middleware.rs
+++ b/crates/openfang-api/src/middleware.rs
@@ -52,30 +52,8 @@ pub async fn auth(
request: Request
,
next: Next,
) -> Response {
- // If no API key configured, restrict to loopback addresses only.
+ // If no API key configured, skip authentication entirely (open access).
if api_key.is_empty() {
- let is_loopback = request
- .extensions()
- .get::>()
- .map(|ci| ci.0.ip().is_loopback())
- .unwrap_or(false);
-
- if !is_loopback {
- tracing::warn!(
- "Rejected non-localhost request: no API key configured. \
- Set api_key in config.toml for remote access."
- );
- return Response::builder()
- .status(StatusCode::FORBIDDEN)
- .header("content-type", "application/json")
- .body(Body::from(
- serde_json::json!({
- "error": "No API key configured. Remote access denied. Configure api_key in ~/.openfang/config.toml"
- })
- .to_string(),
- ))
- .unwrap_or_default();
- }
return next.run(request).await;
}
diff --git a/crates/openfang-kernel/src/kernel.rs b/crates/openfang-kernel/src/kernel.rs
index 7ba9a345..59ee1c19 100644
--- a/crates/openfang-kernel/src/kernel.rs
+++ b/crates/openfang-kernel/src/kernel.rs
@@ -4666,7 +4666,7 @@ fn infer_provider_from_model(model: &str) -> Option {
"minimax" | "gemini" | "anthropic" | "openai" | "groq" | "deepseek" | "mistral"
| "cohere" | "xai" | "ollama" | "together" | "fireworks" | "perplexity"
| "cerebras" | "sambanova" | "replicate" | "huggingface" | "ai21" | "codex"
- | "claude-code" | "copilot" | "github-copilot" | "qwen" | "zhipu" | "moonshot"
+ | "claude-code" | "copilot" | "github-copilot" | "qwen" | "zhipu" | "zai" | "moonshot"
| "openrouter" | "volcengine" | "doubao" | "dashscope" => {
return Some(prefix.to_string());
}
diff --git a/crates/openfang-runtime/src/drivers/mod.rs b/crates/openfang-runtime/src/drivers/mod.rs
index 134b2a81..e8846094 100644
--- a/crates/openfang-runtime/src/drivers/mod.rs
+++ b/crates/openfang-runtime/src/drivers/mod.rs
@@ -18,7 +18,7 @@ use openfang_types::model_catalog::{
MINIMAX_BASE_URL, MISTRAL_BASE_URL, MOONSHOT_BASE_URL, OLLAMA_BASE_URL, OPENAI_BASE_URL,
OPENROUTER_BASE_URL, PERPLEXITY_BASE_URL, QIANFAN_BASE_URL, QWEN_BASE_URL,
REPLICATE_BASE_URL, SAMBANOVA_BASE_URL, TOGETHER_BASE_URL, VLLM_BASE_URL, VOLCENGINE_BASE_URL,
- XAI_BASE_URL, ZHIPU_BASE_URL, ZHIPU_CODING_BASE_URL,
+ XAI_BASE_URL, ZAI_BASE_URL, ZAI_CODING_BASE_URL, ZHIPU_BASE_URL, ZHIPU_CODING_BASE_URL,
};
use std::sync::Arc;
@@ -168,6 +168,16 @@ fn provider_defaults(provider: &str) -> Option {
api_key_env: "ZHIPU_API_KEY",
key_required: true,
}),
+ "zai" => Some(ProviderDefaults {
+ base_url: ZAI_BASE_URL,
+ api_key_env: "ZHIPU_API_KEY",
+ key_required: true,
+ }),
+ "zai_coding" => Some(ProviderDefaults {
+ base_url: ZAI_CODING_BASE_URL,
+ api_key_env: "ZHIPU_API_KEY",
+ key_required: true,
+ }),
"qianfan" | "baidu" => Some(ProviderDefaults {
base_url: QIANFAN_BASE_URL,
api_key_env: "QIANFAN_API_KEY",
diff --git a/crates/openfang-runtime/src/model_catalog.rs b/crates/openfang-runtime/src/model_catalog.rs
index a622971c..968c95d7 100644
--- a/crates/openfang-runtime/src/model_catalog.rs
+++ b/crates/openfang-runtime/src/model_catalog.rs
@@ -10,7 +10,7 @@ use openfang_types::model_catalog::{
LMSTUDIO_BASE_URL, MINIMAX_BASE_URL, MISTRAL_BASE_URL, MOONSHOT_BASE_URL, OLLAMA_BASE_URL,
OPENAI_BASE_URL, OPENROUTER_BASE_URL, PERPLEXITY_BASE_URL, QIANFAN_BASE_URL, QWEN_BASE_URL,
REPLICATE_BASE_URL, SAMBANOVA_BASE_URL, TOGETHER_BASE_URL, VLLM_BASE_URL, VOLCENGINE_BASE_URL,
- XAI_BASE_URL, ZHIPU_BASE_URL, ZHIPU_CODING_BASE_URL,
+ XAI_BASE_URL, ZAI_BASE_URL, ZAI_CODING_BASE_URL, ZHIPU_BASE_URL, ZHIPU_CODING_BASE_URL,
};
use std::collections::HashMap;
@@ -592,6 +592,24 @@ fn builtin_providers() -> Vec {
auth_status: AuthStatus::Missing,
model_count: 0,
},
+ ProviderInfo {
+ id: "zai".into(),
+ display_name: "Z.AI".into(),
+ api_key_env: "ZHIPU_API_KEY".into(),
+ base_url: ZAI_BASE_URL.into(),
+ key_required: true,
+ auth_status: AuthStatus::Missing,
+ model_count: 0,
+ },
+ ProviderInfo {
+ id: "zai_coding".into(),
+ display_name: "Z.AI Coding".into(),
+ api_key_env: "ZHIPU_API_KEY".into(),
+ base_url: ZAI_CODING_BASE_URL.into(),
+ key_required: true,
+ auth_status: AuthStatus::Missing,
+ model_count: 0,
+ },
ProviderInfo {
id: "moonshot".into(),
display_name: "Moonshot (Kimi)".into(),
diff --git a/crates/openfang-types/src/model_catalog.rs b/crates/openfang-types/src/model_catalog.rs
index 7b97ed0c..6883f68f 100644
--- a/crates/openfang-types/src/model_catalog.rs
+++ b/crates/openfang-types/src/model_catalog.rs
@@ -37,6 +37,9 @@ pub const QWEN_BASE_URL: &str = "https://dashscope.aliyuncs.com/compatible-mode/
pub const MINIMAX_BASE_URL: &str = "https://api.minimax.io/v1";
pub const ZHIPU_BASE_URL: &str = "https://open.bigmodel.cn/api/paas/v4";
pub const ZHIPU_CODING_BASE_URL: &str = "https://open.bigmodel.cn/api/coding/paas/v4";
+/// Z.AI domain aliases (same API, different domain).
+pub const ZAI_BASE_URL: &str = "https://api.z.ai/api/paas/v4";
+pub const ZAI_CODING_BASE_URL: &str = "https://api.z.ai/api/coding/paas/v4";
pub const MOONSHOT_BASE_URL: &str = "https://api.moonshot.cn/v1";
pub const QIANFAN_BASE_URL: &str = "https://qianfan.baidubce.com/v2";
pub const VOLCENGINE_BASE_URL: &str = "https://ark.cn-beijing.volces.com/api/v3";