diff --git a/CHANGELOG.md b/CHANGELOG.md index d6b0ad635..e9e08a28d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ ### 修复 +- 知识库接口对调用方传入的非法路径(含 `..`、空/根目录)返回 400 `KNOWLEDGE_PATH_INVALID`,不再打堆栈返回 500(#909) - 企查查在对话中改为按内部 HTTP MCP 加载工具(`mcp_mode=internal`),不再误走进程内 gateway 导致「无法加载 MCP 工具」 - 定时任务以专家方式执行时,运行失败(工具调用报错、需要人工介入、没有可见回复)也会把任务提示词和已产出的部分内容投影进会话线程;此前这些线程一个字都没有,点「立即执行」后打开对话只看到空会话(#516) diff --git a/src/octop/api/routers/knowledge_bases.py b/src/octop/api/routers/knowledge_bases.py index 231dfdf82..b31dd4979 100644 --- a/src/octop/api/routers/knowledge_bases.py +++ b/src/octop/api/routers/knowledge_bases.py @@ -243,6 +243,8 @@ def _map_knowledge_error( return OctopError.localized(ErrorCode.KNOWLEDGE_NAME_TAKEN, locale) if "invalid knowledge document name" in text: return OctopError.localized(ErrorCode.KNOWLEDGE_NAME_INVALID, locale) + if "invalid knowledge document path" in text or "invalid knowledge folder path" in text: + return OctopError.localized(ErrorCode.KNOWLEDGE_PATH_INVALID, locale) if "prerequisite" in text or "embedding model" in text or "embedding_model" in text: return OctopError.localized(ErrorCode.KNOWLEDGE_PREREQUISITES_FAILED, locale) logger.exception("unhandled error in knowledge base router: %s", exc) diff --git a/src/octop/i18n/en.json b/src/octop/i18n/en.json index b856f3247..2a7c83307 100644 --- a/src/octop/i18n/en.json +++ b/src/octop/i18n/en.json @@ -426,6 +426,7 @@ "KNOWLEDGE_UNSUPPORTED_TYPE": "This document type is not supported for knowledge bases.", "KNOWLEDGE_NAME_TAKEN": "You already have a knowledge base with this name.", "KNOWLEDGE_NAME_INVALID": "Invalid name.", + "KNOWLEDGE_PATH_INVALID": "Invalid path.", "AVATAR_INVALID": "Avatar must be a PNG, JPEG, WebP, or GIF image.", "AVATAR_TOO_LARGE": "Avatar exceeds the 5 MB size limit.", "INVITE_INVALID": "This invite code is invalid.", diff --git a/src/octop/i18n/zh.json b/src/octop/i18n/zh.json index bde66143a..a22cadbf2 100644 --- a/src/octop/i18n/zh.json +++ b/src/octop/i18n/zh.json @@ -426,6 +426,7 @@ "KNOWLEDGE_UNSUPPORTED_TYPE": "知识库不支持此文档类型。", "KNOWLEDGE_NAME_TAKEN": "您已有同名知识库。", "KNOWLEDGE_NAME_INVALID": "名称无效。", + "KNOWLEDGE_PATH_INVALID": "路径无效。", "AVATAR_INVALID": "头像须为 PNG、JPEG、WebP 或 GIF 图片。", "AVATAR_TOO_LARGE": "头像超过 5 MB 大小限制。", "INVITE_INVALID": "邀请码无效。", diff --git a/src/octop/infra/errors.py b/src/octop/infra/errors.py index 29348b25d..b05d34b2c 100644 --- a/src/octop/infra/errors.py +++ b/src/octop/infra/errors.py @@ -100,6 +100,7 @@ class ErrorCode(StrEnum): KNOWLEDGE_UNSUPPORTED_TYPE = "KNOWLEDGE_UNSUPPORTED_TYPE" KNOWLEDGE_NAME_TAKEN = "KNOWLEDGE_NAME_TAKEN" KNOWLEDGE_NAME_INVALID = "KNOWLEDGE_NAME_INVALID" + KNOWLEDGE_PATH_INVALID = "KNOWLEDGE_PATH_INVALID" AVATAR_INVALID = "AVATAR_INVALID" AVATAR_TOO_LARGE = "AVATAR_TOO_LARGE" INVITE_INVALID = "INVITE_INVALID" @@ -210,6 +211,7 @@ class ErrorCode(StrEnum): ErrorCode.KNOWLEDGE_UNSUPPORTED_TYPE: 400, ErrorCode.KNOWLEDGE_NAME_TAKEN: 409, ErrorCode.KNOWLEDGE_NAME_INVALID: 400, + ErrorCode.KNOWLEDGE_PATH_INVALID: 400, ErrorCode.AVATAR_INVALID: 400, ErrorCode.AVATAR_TOO_LARGE: 413, ErrorCode.INVITE_INVALID: 400, diff --git a/tests/unit/api/test_knowledge_bases.py b/tests/unit/api/test_knowledge_bases.py index d5069bfe8..c69d2e390 100644 --- a/tests/unit/api/test_knowledge_bases.py +++ b/tests/unit/api/test_knowledge_bases.py @@ -718,6 +718,21 @@ def test_map_knowledge_error_unclassified_returns_internal_error() -> None: assert err_generic.status == 500 +@pytest.mark.parametrize( + "message", + [ + "invalid knowledge document path", + "invalid knowledge folder path", + ], +) +def test_map_knowledge_error_invalid_path_returns_400(message: str) -> None: + from octop.api.routers.knowledge_bases import _map_knowledge_error + + err = _map_knowledge_error(ValueError(message), locale="en") + assert err.code == ErrorCode.KNOWLEDGE_PATH_INVALID + assert err.status == 400 + + def test_map_knowledge_error_prerequisites_distinguished() -> None: from octop.api.routers.knowledge_bases import _map_knowledge_error