Skip to content

feat: support ai gateway yaml import and export in ui and e2e flows - #3146

Merged
cszmzh merged 8 commits into
TencentBlueKing:masterfrom
cszmzh:ft_ai_gateway_yaml_import_export
Aug 12, 2026
Merged

feat: support ai gateway yaml import and export in ui and e2e flows#3146
cszmzh merged 8 commits into
TencentBlueKing:masterfrom
cszmzh:ft_ai_gateway_yaml_import_export

Conversation

@cszmzh

@cszmzh cszmzh commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator
  • 支持 AI 网关资源 YAML 的页面导入导出及 e2e 导入。

@cszmzh
cszmzh requested a review from wklken August 10, 2026 12:54
Comment thread src/dashboard/apigateway/apigateway/biz/resource_doc/importer/parsers.py Outdated
Comment thread src/dashboard/apigateway/apigateway/apis/web/resource/serializers.py Outdated

@wklken wklken left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #3146 合并 Review 报告(Codex + Claude 双模型汇总)

  • 标题:feat: support ai gateway yaml import and export in ui and e2e flows
  • 作者:cszmzh (Zach)
  • 分支ft_ai_gateway_yaml_import_exportmaster
  • 规模:13 个文件,+333 / -93(diff 638 行)
  • 重心:3 份 OpenAPI schema JSON(各 48 行)、biz/openapi/openapi.py(54 行)、v2 sync 测试(112 行)

本报告由 github-pr-monitor 双模型(Codex gpt-5.6-sol + Claude Opus 5)独立 review 后汇总。两个模型结论高度一致。

汇总结论

合并建议:merge after fixes(修复后合并)

两个 reviewer 均确认存在一处硬阻塞(Critical):parsers.py:178 的 Python 3 语法错误导致模块无法 import,资源文档导入功能整体不可用。另有若干 High / Medium / Low 级别问题需处理后合并或跟进。


Critical Issues(合并前必须修复)

[C1] parsers.py:178 使用 Python 2 异常语法,模块无法 import 🔴

src/dashboard/apigateway/apigateway/biz/resource_doc/importer/parsers.py:178

try:
    openapi_manager.parse_schema()
except ResolutionError, ValueError:   # ← SyntaxError
    raise SchemaValidationError("") from None

except A, B: 是 Python 2 语法,Python 3 必须用括号:except (ResolutionError, ValueError):。这是模块级语法错误,任何 import 该模块的代码都会立即抛 SyntaxError,不限于某个运行时分支。该模块承载 OpenAPIParser / 资源文档导入解析,属于导入链路主路径,会导致资源文档导入整体不可用,且 pytest 在收集阶段即失败。Claude 已用 ast.parse 实测确认。

修复

except (ResolutionError, ValueError) as err:
    raise SchemaValidationError(str(err)) from None

该语法错误说明本 PR 未执行 ruff / pytest。按 src/dashboard/AGENTS.md 的 Post-Implementation Requirements,合并前必须补跑:
uv run make edition-ee && uv run make lint-check 及相关 pytest 目标。


High Issues(应该修复)

[H1] ResourceDataImportSLZ.to_internal_value 绕过 DRF Mapping 守卫,非法入参从 400 退化为 500

serializers.py:721

def to_internal_value(self, data):
    # 兼容资源导入页面将模型代理 API 的空后端配置提交为 {} 的场景。
    if data.get("kind") == ResourceKindEnum.AI.value and data.get("backend_config") == {}:
        data = {**data, "backend_config": None}
    return super().to_internal_value(data)

覆写在调用 super().to_internal_value(data) 之前就执行 data.get(...),绕过了 DRF Serializer.to_internal_value 首行的 if not isinstance(data, Mapping): raise ValidationError(...) 守卫。该 SLZ 通过 ResourceImportInputSLZ.import_resources = ListField(child=ResourceDataImportSLZ()) 使用,客户端传入 {"import_resources": ["foo"]}[[1, 2]]datastr/list,直接抛 AttributeError: 'str' object has no attribute 'get' → 未捕获 → HTTP 500(正确行为应为 400)。同一路径被 ResourceImportDocPreviewInputSLZ.review_resourceserializers.py:775)复用。

修复:先判断类型再兼容处理:

def to_internal_value(self, data):
    if (
        isinstance(data, Mapping)
        and data.get("kind") == ResourceKindEnum.AI.value
        and data.get("backend_config") == {}
    ):
        data = {**data, "backend_config": None}
    return super().to_internal_value(data)

[H2] 本 PR 唯一改动语义的文档导入路径(parsers.py)零测试覆盖

parsers.pyvalidate() 切换为 validate_schema() + parse_schema() 两段式调用,是本 PR 语义变化最大的一处(校验范围从"schema + 业务校验"收窄为"仅 schema"),但新增测试全部集中在 v2 sync / resource import / resource_version 导出,没有任何一条覆盖 OpenAPIParser._parse。这正是 C1 语法错误能被提交的直接原因。建议至少补两条用例:schema 非法时 SchemaValidationError 的 message 非空且包含 json_path$ref 解析失败时走 ResolutionError 分支。


Medium Issues(风险较低,建议处理)

[M1] 文档导入由 validate() 收窄为 validate_schema(),业务校验缺失

parsers.py:172openapi_manager.validate() 改为 openapi_manager.validate_schema()。对照 biz/openapi/openapi.pyvalidate() = validate_schema() + ResourceImportValidator.validate()(承载 _validate_kind、资源数量上限等规则)。改动后文档导入不再拒绝业务层非法资源。逻辑上可能合理(文档导入只需 schema 合法,避免 AI 资源因后端未创建而无法生成文档),但属于行为变更,diff 无注释、PR 描述无说明。建议在 _parse 处补一行注释说明"文档导入仅需 schema 合法,业务校验由资源导入链路负责",避免后续被误当回归改回。

[M2] SchemaValidationError("") 丢弃底层错误信息

parsers.py:179ResolutionError / ValueError 的原因完全丢掉,且 from None 抑制异常链,用户与日志都拿不到线索。$ref 无法解析是 YAML 导入最常见失败之一。修 C1 时一并带上 str(err)

[M3] BaseParser.get_resourcesbackend is None 缺少防御

biz/openapi/parser.py:59-63 改动后 kind == ai 时不再补默认 backend,backend 可能为 None;而 parser.py:79 无条件调用 backend.get("name", ...)。当前被远端 schema(ai 分支 required: ["kind", "backend"])屏蔽,不可从 HTTP 触发,故未升级为 High,但属纯靠 schema 维持的隐式不变量——任何未先跑 schema 的新调用方都会 AttributeError。建议显式处理:

backend = extension_resource.get("backend")
if kind != ResourceKindEnum.AI.value:
    backend = backend or {...}
elif backend is None:
    raise ValueError(_("模型代理资源必须指定 backend"))

(抛 ValueError 可被 openapi.py:43except (ResolutionError, ValueError) 收敛,与既有风格一致。)

[M4] AI 资源"空后端配置"存在 {}None 两种表示,契约不自闭合

serializers.py:849 把 check 接口输出改成 {"name": ..., "config": None},而 to_internal_value 又把提交上来的 backend_config == {} 归一成 None。导出用 None、导入额外容忍 {}。新增测试本身暴露了这一点(喂回 import 前必须手工 pop("backend") 并把 backend_config 写成 {})。建议二选一:让前端统一提交 None 并删除兼容代码;或在注释中标注这是过渡期兼容并记录清理条件(关联 issue / 前端版本)。


Low Issues(轻微改进建议)

  • [L1] service/resource_version/openapi_export.py:142responses 兜底用 if "responses" not in operation,未覆盖 responses: {} 空 dict 情况。建议改为 if not operation.get("responses"):
  • [L2] _validate_refsvalidate()+parse() 流程中被重复执行(validate_schemaparse_schema 各调一次),行为正确(幂等),属已知冗余。
  • [L3] data/apidocs/zh/sync_resources.mdv2_sync_resources.md 新增的 AI 网关资源 YAML 说明内容完全一致,后续需同步维护。

Dismissed Findings(已驳回,不计入问题)

  • oneOf 会破坏省略 kind / kind: ai 的校验:不成立。逐分支推演,kind 缺失恰好命中分支 2(非 name-only 普通资源),kind: ai 必然落空于分支 2(其 enum=["standard"]),两分支互斥,与文档"使用 kind: standard 或省略 kind"一致。
  • backend: {name: "default"}(仅 name)的普通资源会被 schema 拒:确实会拒,但改动前的 allOf[anyOf[...]] 对同一输入同样拒绝,属既有行为而非本 PR 回归。
  • to_internal_valuedata = {**data, ...} 会污染调用方入参:不成立,浅拷贝新建 dict,写法正确。
  • 英文文档 data/apidocs/en/ 未同步更新:不成立,data/apidocs/ 下只有 zh 子目录,无英文副本需同步。

双模型一致性

Issue Codex Claude Verdict
C1 parsers.py:178 语法错误 是(ast.parse 实测) 真实问题(硬阻塞)
H1 to_internal_value 类型守卫缺失 真实问题(Claude 检出,建议补测)
H2 parsers.py 零测试覆盖 真实问题
M1 业务校验缺失 需人工确认(疑似有意为之)
M2 错误信息被丢弃 真实问题
M3 backend None 缺防御 潜在问题
M4 {}/None 双表示 设计取舍
L1-L3 轻微

合并建议

merge after fixes(修复后合并)

方向良好:oneOf 把"AI 资源 backend 仅含 name"与"普通资源 backend 必须含请求配置"表达为两个互斥分支,比原 allOf[anyOf[...]] 清晰;三份 schema(2.0/3.0/3.1)改动完全一致无漏改;validate/validate_schemaparse/parse_schema 的拆分让文档导入不必承担资源落库校验,分层符合 AGENTS.md 职责划分;中文文档同步补充了 AI 资源 YAML 说明。

阻塞项(必须修后合并)

  1. C1except ResolutionError, ValueError: 硬语法错误,模块无法 import,资源文档导入不可用,pytest 收集即失败。
  2. H1to_internal_value 绕过 DRF Mapping 守卫,非法入参从 400 退化为 500。

建议一并处理:M2(顺手在 C1 修复中带 str(err))、M3(显式拒绝 backend is None)、H2(为 OpenAPIParser._parse 补 2 条用例)。

由于 C1 存在可确定本 PR 未执行 lint 与测试,修复后请务必按 src/dashboard/AGENTS.md 补跑 uv run make edition-ee && uv run make lint-check 及相关 pytest 目标。

[from openclaw-internal]

@cszmzh

cszmzh commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

C1 / H1 / H2 / M1 / M2 / M4 fix

@cszmzh
cszmzh requested a review from wklken August 11, 2026 08:51
Comment thread src/dashboard/apigateway/apigateway/data/apidocs/zh/v2_sync_resources.md Outdated
Comment thread src/dashboard/apigateway/apigateway/data/apidocs/zh/sync_resources.md Outdated
Comment thread src/dashboard/apigateway/apigateway/biz/openapi/schemas/openapi_3.0_schema.json Outdated
Comment thread src/dashboard/apigateway/apigateway/biz/openapi/schemas/openapi_3.0_schema.json Outdated
Comment thread src/dashboard/apigateway/apigateway/apis/web/resource/views.py
Comment thread src/dashboard/apigateway/apigateway/biz/openapi/schemas/openapi_3.0_schema.json Outdated
@cszmzh
cszmzh requested a review from wklken August 11, 2026 13:06
Comment thread src/dashboard/apigateway/apigateway/biz/openapi/schemas/openapi_2.0_schema.json Outdated
Comment thread src/dashboard/apigateway/apigateway/service/resource_version/openapi_export.py Outdated
@cszmzh
cszmzh merged commit 3af6c41 into TencentBlueKing:master Aug 12, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants