diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a28b3a..ee0047a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # 更新日志 +## 0.2.16 - 2026-07-07 + +- 修复 AI 内置页面工具在配置了受保护公开地址时,请求 `/v1/web/pages` 命中 NetBird 鉴权页并返回 401 的问题。 +- `create_web_page`、`create_markdown_preview`、`query_web_pages` 的内部 HTTP 请求现在优先使用 `IA_WEB_INTERNAL_URL` 或本地 `HOST`;返回给用户的页面链接仍优先使用 `IA_WEB_BASE_URL`。 +- `query_api_docs` 同步优先使用内部地址查询 API 文档,避免内部工具调用被公开入口鉴权拦截。 +- 无数据库结构变化;新增 `0.2.16` 升级日志记录,`ias-ai` 升级至 `0.1.6`,`ias-service` 升级至 `0.1.13`。 + ## 0.2.15 - 2026-07-07 - 新增 Markdown 预览页面能力:`page_type=markdown` 的动态页面公开路径为 `/md/{slug}`,React 前端按 Markdown/GFM 渲染标题、列表、表格、引用、链接和代码块。 diff --git a/Cargo.lock b/Cargo.lock index bc81797..86c6316 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1042,7 +1042,7 @@ dependencies = [ [[package]] name = "ias-ai" -version = "0.1.5" +version = "0.1.6" dependencies = [ "anyhow", "chrono", @@ -1120,7 +1120,7 @@ dependencies = [ [[package]] name = "ias-main" -version = "0.2.15" +version = "0.2.16" dependencies = [ "anyhow", "clap", @@ -1135,7 +1135,7 @@ dependencies = [ [[package]] name = "ias-service" -version = "0.1.12" +version = "0.1.13" dependencies = [ "anyhow", "axum", diff --git a/VERSION b/VERSION index b005e30..9097948 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.15 +0.2.16 diff --git a/ias-ai/Cargo.toml b/ias-ai/Cargo.toml index 897ce7a..fefc7fb 100644 --- a/ias-ai/Cargo.toml +++ b/ias-ai/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ias-ai" -version = "0.1.5" +version = "0.1.6" edition = "2024" [dependencies] diff --git a/ias-ai/src/tools/api_docs.rs b/ias-ai/src/tools/api_docs.rs index ac78982..b1dd91d 100644 --- a/ias-ai/src/tools/api_docs.rs +++ b/ias-ai/src/tools/api_docs.rs @@ -196,8 +196,7 @@ fn validate_endpoint_id(value: &str) -> anyhow::Result { fn api_docs_base_url() -> String { std::env::var("IA_API_DOCS_BASE_URL") - .or_else(|_| std::env::var("IA_WEB_BASE_URL")) - .or_else(|_| std::env::var("WEB_BASE_URL")) + .or_else(|_| std::env::var("IA_WEB_INTERNAL_URL")) .or_else(|_| std::env::var("HOST").map(|host| format!("http://{host}"))) .unwrap_or_else(|_| "http://127.0.0.1:9003".to_string()) .trim() diff --git a/ias-ai/src/tools/web.rs b/ias-ai/src/tools/web.rs index 0fcb0d3..ac4da08 100644 --- a/ias-ai/src/tools/web.rs +++ b/ias-ai/src/tools/web.rs @@ -129,7 +129,7 @@ async fn create_markdown_preview_inner(arguments: &str) -> anyhow::Result anyhow::Result { - let base_url = web_base_url(); + let base_url = web_request_base_url(); let endpoint = format!("{base_url}/v1/web/pages"); let client = reqwest::Client::new(); let response = client @@ -184,7 +184,7 @@ async fn query_web_pages_inner(arguments: &str) -> anyhow::Result { let page = args.page.unwrap_or(1).max(1); let per_page = args.per_page.unwrap_or(10).clamp(1, 20); - let mut url = reqwest::Url::parse(&format!("{}/v1/web/pages", web_base_url())) + let mut url = reqwest::Url::parse(&format!("{}/v1/web/pages", web_request_base_url())) .context("构造 web 页面查询地址失败")?; { let mut query_pairs = url.query_pairs_mut(); @@ -266,7 +266,7 @@ fn web_page_url(page: &WebPageItem) -> String { } else { format!("/web/{}/{}", page.page_type, page.slug) }; - format!("{}{}", web_base_url(), path) + format!("{}{}", web_public_base_url(), path) } fn optional_text(value: Option) -> Option { @@ -275,7 +275,16 @@ fn optional_text(value: Option) -> Option { .filter(|value| !value.is_empty()) } -fn web_base_url() -> String { +fn web_request_base_url() -> String { + std::env::var("IA_WEB_INTERNAL_URL") + .or_else(|_| std::env::var("HOST").map(|host| format!("http://{host}"))) + .unwrap_or_else(|_| "http://127.0.0.1:9003".to_string()) + .trim() + .trim_end_matches('/') + .replace("0.0.0.0", "127.0.0.1") +} + +fn web_public_base_url() -> String { std::env::var("IA_WEB_BASE_URL") .or_else(|_| std::env::var("WEB_BASE_URL")) .or_else(|_| std::env::var("HOST").map(|host| format!("http://{host}"))) diff --git a/ias-main/Cargo.toml b/ias-main/Cargo.toml index df15f4b..3f2823b 100644 --- a/ias-main/Cargo.toml +++ b/ias-main/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ias-main" -version = "0.2.15" +version = "0.2.16" edition = "2024" [[bin]] diff --git a/ias-service/Cargo.toml b/ias-service/Cargo.toml index 1f23315..2396b6c 100644 --- a/ias-service/Cargo.toml +++ b/ias-service/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ias-service" -version = "0.1.12" +version = "0.1.13" edition = "2024" [dependencies] diff --git a/ias-service/migrations/20260707014000_insert_upgrade_log_0_2_16.sql b/ias-service/migrations/20260707014000_insert_upgrade_log_0_2_16.sql new file mode 100644 index 0000000..c24c985 --- /dev/null +++ b/ias-service/migrations/20260707014000_insert_upgrade_log_0_2_16.sql @@ -0,0 +1,34 @@ +INSERT INTO ias_upgrade_logs ( + version, + released_at, + title, + description, + changes, + modules +) VALUES ( + '0.2.16', + '2026-07-07T00:00:00+08:00', + '修复 AI 页面工具内部访问地址', + '修复 AI 内置页面工具在公开地址受 NetBird 鉴权保护时无法创建 Markdown 预览页的问题,内部请求改为优先使用内部地址或本地服务地址。', + '[ + "修复 AI 内置页面工具在配置了受保护公开地址时,请求 /v1/web/pages 命中 NetBird 鉴权页并返回 401 的问题。", + "create_web_page、create_markdown_preview、query_web_pages 的内部 HTTP 请求现在优先使用 IA_WEB_INTERNAL_URL 或本地 HOST;返回给用户的页面链接仍优先使用 IA_WEB_BASE_URL。", + "query_api_docs 同步优先使用内部地址查询 API 文档,避免内部工具调用被公开入口鉴权拦截。", + "无数据库结构变化;ias-ai 升级至 0.1.6,ias-service 升级至 0.1.13。" + ]'::jsonb, + '{ + "ias-common": "0.1.1", + "ias-ai": "0.1.6", + "ias-wechat": "0.1.0", + "ias-context": "0.1.2", + "ias-http": "0.1.9", + "ias-mail": "0.1.15", + "ias-service": "0.1.13", + "ias-main": "0.2.16" + }'::jsonb +) ON CONFLICT (version) DO UPDATE SET + released_at = EXCLUDED.released_at, + title = EXCLUDED.title, + description = EXCLUDED.description, + changes = EXCLUDED.changes, + modules = EXCLUDED.modules;