asset.list 的 kind 过滤改为拒绝非 canonical 值
- direct_tool_bridge.rs:`kind` 收口后既不是 canonical、也不是字面 `unknown` 时直接返回工具错误并带上原值,不再静默过滤出空列表。 - direct_tool_bridge.rs:新增用例,钉住"项目访问前就报错"与"字面 `unknown` 仍是合法过滤值"。 - direct_tools_mcp.rs:schema 描述改为必须是 canonical kind、非 canonical 值会被拒绝。
This commit is contained in:
@@ -1245,7 +1245,8 @@ fn bridge_list_registered_assets(root: &Path, arguments: &Value) -> Value {
|
||||
"kind",
|
||||
DIRECT_TOOL_BRIDGE_MAX_RESOURCE_KIND_CHARS,
|
||||
)?
|
||||
.map(|kind| GameCreationAppAssetKind::parse_with_context(&kind, "asset.list.kind"));
|
||||
.map(|kind| bridge_asset_list_kind_filter(&kind))
|
||||
.transpose()?;
|
||||
let asset_id = bridge_optional_bounded_string(
|
||||
arguments,
|
||||
"assetId",
|
||||
@@ -1325,6 +1326,24 @@ fn bridge_list_registered_assets(root: &Path, arguments: &Value) -> Value {
|
||||
}
|
||||
}
|
||||
|
||||
/// `asset.list` 的 `kind` 过滤:只接受 canonical 值,认不出的值直接报错。
|
||||
///
|
||||
/// 以前认不出的值会收口成 `unknown` 再参与等值过滤,结果是**静默返回空列表**:调用方(模型)
|
||||
/// 会以为项目里没有这类资产,而不是"你传的 kind 不合法",于是继续按错误前提往下走。
|
||||
/// `unknown` 本身仍是合法输入(确有 kind 未知的资产),只拒绝"既不是 canonical、也不是字面
|
||||
/// `unknown`"的原值。
|
||||
fn bridge_asset_list_kind_filter(raw: &str) -> Result<GameCreationAppAssetKind, String> {
|
||||
let kind = GameCreationAppAssetKind::parse_with_context(raw, "asset.list.kind");
|
||||
if kind == GameCreationAppAssetKind::Unknown
|
||||
&& raw.trim() != GameCreationAppAssetKind::Unknown.as_str()
|
||||
{
|
||||
return Err(format!(
|
||||
"kind 不是已知的 manifest 资源 kind:{raw};请改用 canonical kind(如 image、scene、character、icon、icon-spritesheet、character-animation、audio、video、document)"
|
||||
));
|
||||
}
|
||||
Ok(kind)
|
||||
}
|
||||
|
||||
fn bridge_project_file_class(path: &str) -> (&'static str, Option<&'static str>) {
|
||||
let extension = Path::new(path)
|
||||
.extension()
|
||||
@@ -2745,6 +2764,28 @@ mod tests {
|
||||
.contains("x-genarrative-client:"));
|
||||
}
|
||||
|
||||
/// `asset.list` 的 `kind` 过滤必须报错,而不是静默返回空列表:旧值会收口成 `unknown` 再参与
|
||||
/// 等值过滤,匹配不到任何资产,让模型误以为项目里没有这类资产。校验必须发生在项目访问之前。
|
||||
#[test]
|
||||
fn bridge_asset_list_rejects_non_canonical_kind_filter() {
|
||||
let root = tempfile::tempdir().expect("bridge root");
|
||||
let rejected =
|
||||
bridge_list_registered_assets(root.path(), &json!({ "kind": "art-spritesheet-slice" }));
|
||||
assert_eq!(rejected["isError"], true);
|
||||
assert!(
|
||||
rejected.to_string().contains("art-spritesheet-slice"),
|
||||
"错误里必须带上原值,调用方才能自纠:{rejected}"
|
||||
);
|
||||
// 字面 `unknown` 仍是合法过滤值:它应当越过 kind 校验,失败点换成项目侧(此目录未初始化)。
|
||||
let allowed = bridge_list_registered_assets(root.path(), &json!({ "kind": "unknown" }));
|
||||
assert!(
|
||||
!allowed
|
||||
.to_string()
|
||||
.contains("不是已知的 manifest 资源 kind"),
|
||||
"未知 kind 的字面量本身是合法输入:{allowed}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bridge_argument_bounds_are_deterministic() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -307,7 +307,7 @@ fn direct_tools_mcp_specs_for(controlled_web_search: bool, _cocos_editor_availab
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 80,
|
||||
"description": "可选的 manifest 资源 kind 精确过滤,例如 video、character-animation、sound-effect、background-music 或 icon-spritesheet"
|
||||
"description": "可选的 manifest 资源 kind 精确过滤,必须是 canonical kind(例如 video、character-animation、sound-effect、background-music、icon-spritesheet);传非 canonical 值会被拒绝并报错,不会静默返回空列表"
|
||||
},
|
||||
"assetId": {
|
||||
"type": "string",
|
||||
|
||||
Reference in New Issue
Block a user