Prhub

#44299 [Rust Frontend] Support recursive tool parameter conversion

原始 PR 作者 BugenZhao 合并时间 2026-06-02 22:45 文件变更 2 提交数 3 评论 2 代码增减 +435 / -79

执行摘要

支持递归工具参数类型转换

目前工具参数转换仅支持原始字符串输入,无法处理未来解析器可能产生的结构化参数(如嵌套对象)。PR 旨在扩展转换工具,使其能够递归处理任意深度的参数模式,同时保持对现有字符串解析器的向前兼容。

建议合并,但需关注空字符串行为变化,考虑补充对应测试或文档说明。设计模式值得学习:使用 Into<ParamInput> 桥接新旧输入,以及递归模式处理策略。

讨论亮点

Chatgpt-codex-connector 指出当字符串解析器传入空值时,对象/数组参数现在会返回 {}[] 而非原始字符串 "",这可能与 '保留原始字符串行为' 的承诺冲突。这是一处 P2 级潜在回归,但作者未在评论线程中回应。评审者 njhill 批准了 PR。

实现拆解

  1. 引入 ParamInput 和 ParamElement 类型:在 parameters.rs 中添加 ParamInput 枚举(TextElements)和 ParamElement 结构体,作为解析器中立的参数输入表示。通过 From<String> 实现,现有字符串调用者可无缝迁移。
  2. 扩展 JsonParamType 为递归结构:将 ObjectArray 变体从无参数改为包含子类型映射。Object 现在携带 properties: BTreeMap<String, JsonParamType>additional_properties: Option<Box<JsonParamType>>Array 携带 items: Option<Box<JsonParamType>>。这允许模式递归嵌套。
  3. 重写 from_schema 方法:递归解析嵌套模式。新增辅助函数 from_type_valuefrom_type_nameobject_from_schemaarray_from_schema,处理 typepropertiesadditionalPropertiesitemsanyOf 等 JSON Schema 关键字。
  4. 重写转换逻辑:新增 convert_with_optional_schematry_convert_value 函数,根据 ParamInputText 还是 Elements 分别处理:文本输入尝试根据类型解析 JSON 字面量;结构化输入递归遍历元素,根据模式转换每个子值。对于未知的参数名,结构化输入会回退到 '对象式 JSON'。
  5. 适配现有调用者convert_params_with_schemaconvert_param_with_schema 改为泛型 P: Into<ParamInput>,调用点只需传递值(如 param.value 而非 &param.value)。DeepSeek DSML 解析器中对应调整一行。所有测试通过。
文件 模块 状态 重要度
rust/src/tool-parser/src/parameters.rs 解析器 modified 8.93
rust/src/tool-parser/src/deepseek_dsml/mod.rs 解析器 modified 4.54

关键符号

from_schema convert_with_optional_schema try_convert_value from_type_value from_type_name object_from_schema array_from_schema convert_param_with_schema convert_params_with_schema

关键源码片段

rust/src/tool-parser/src/parameters.rs core-logic

核心实现文件,包含所有新增类型和递归转换逻辑。

// 新的 JsonParamType 支持递归嵌套
#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) enum JsonParamType {
    String,
    Integer,
    Number,
    Boolean,
    Object {
        properties: BTreeMap<String, JsonParamType>,
        additional_properties: Option<Box<JsonParamType>>,
    },
    Array {
        items: Option<Box<JsonParamType>>,
    },
    Null,
    OneOf(Vec<JsonParamType>),
}// 根据可选的模式进行递归转换
fn convert_with_optional_schema(
    param_type: Option<&JsonParamType>,
    input: &ParamInput,
) -> Value {
    // 如果输入是文本且为 "null",直接返回 JSON null
    if let ParamInput::Text(value) = input
        && value.eq_ignore_ascii_case("null")
    {
        return Value::Null;
    }    // 如果提供了模式,则用模式转换
    if let Some(param_type) = param_type {
        return try_convert_value(param_type, input);
    }    // 无模式时的回退:根据输入类型尽力转换
    match input {
        ParamInput::Text(value) => Value::String(value.clone()),
        ParamInput::Elements(elements) => {
            // 将命名元素递归转换为 JSON 对象
            let mut map = Map::new();
            for element in elements {
                let value = convert_with_optional_schema(None, &element.value);
                map.insert(element.name.clone(), value);
            }
            Value::Object(map)
        }
    }
}

评论区精华

空字符串行为变更 正确性

Chatgpt-codex-connector 指出当字符串解析器传入空值时,对象 / 数组参数现在会返回 {} 或 [] 而非原始字符串,可能违背承诺。

结论:作者未回应,评审者仍批准合并。 · unresolved

风险与影响

主要风险来自 convert_with_optional_schema 中对空字符串的处理:现在空字符串在对象/数组模式下会被转换为 {}/[],而不是保持为 ""。这可能影响依赖原始字符串行为的解析器(如 DSML 或 XML 后端)。此外,新引入的递归逻辑可能因复杂模式导致栈溢出,但 Rust 的递归深度在典型场景下足够。缺少针对结构化输入的显式测试(仅单元测试,但未覆盖所有边界)。

对用户无直接可见影响,因为这是后端重构,且未注册新解析器。对开发者,新的递归能力为未来结构化解析器注册铺平了道路。现有字符串解析器行为在绝大多数场景下保持不变,但空值处理存在微小差异。系统影响仅限于 Rust 工具解析模块。

行为变更 空值处理 递归深度风险

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论