Files
Aether/tests/unit/test_body_rules.py
fawney19 d026398bab refactor(body-rules): 移除 protected_body_keys 机制,允许 body_rules 自由修改所有请求体字段
删除 get_cache_sensitive_protected_body_keys 函数及相关常量、_is_protected_path
辅助函数,从 apply_body_rules、RequestBuilder、ProviderRequestResult 等处移除
protected_body_keys 参数,更新所有调用点和测试用例。
2026-03-18 10:52:07 +08:00

1619 lines
54 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from typing import Any
from src.api.handlers.base.request_builder import (
apply_body_rules,
)
class TestApplyBodyRulesNestedPaths:
def test_set_nested_value(self) -> None:
body = {"a": 1}
result = apply_body_rules(
body,
[
{"action": "set", "path": "b.c.d", "value": 42},
],
)
assert result == {"a": 1, "b": {"c": {"d": 42}}}
def test_drop_nested_value(self) -> None:
body = {"a": {"b": {"c": 1, "d": 2}}}
result = apply_body_rules(
body,
[
{"action": "drop", "path": "a.b.c"},
],
)
assert result == {"a": {"b": {"d": 2}}}
def test_rename_nested_value(self) -> None:
body = {"old": {"nested": "value"}}
result = apply_body_rules(
body,
[
{"action": "rename", "from": "old.nested", "to": "new.path"},
],
)
assert result == {"old": {}, "new": {"path": "value"}}
def test_top_level_keys_can_be_updated(self) -> None:
body = {"model": "gpt-4", "extra": {"model": "ignored"}}
result = apply_body_rules(
body,
[
{"action": "set", "path": "model", "value": "gpt-4.1"},
{"action": "set", "path": "extra.model", "value": "y"},
],
)
assert result["model"] == "gpt-4.1"
assert result["extra"]["model"] == "y"
def test_escaped_dot(self) -> None:
body: dict[str, Any] = {}
result = apply_body_rules(
body,
[
{"action": "set", "path": "config\\.v1.enabled", "value": True},
],
)
assert result == {"config.v1": {"enabled": True}}
def test_invalid_paths_are_ignored(self) -> None:
body = {"a": 1}
result = apply_body_rules(
body,
[
{"action": "set", "path": ".b", "value": 2},
{"action": "set", "path": "c..d", "value": 3},
{"action": "drop", "path": "e.", "value": None},
{"action": "rename", "from": "x..y", "to": "z", "value": None},
],
)
assert result == {"a": 1}
def test_non_dict_intermediate_is_overwritten(self) -> None:
body = {"a": 1}
result = apply_body_rules(
body,
[
{"action": "set", "path": "a.b", "value": 2},
],
)
assert result == {"a": {"b": 2}}
def test_set_complex_value(self) -> None:
body: dict[str, Any] = {}
result = apply_body_rules(
body,
[
{"action": "set", "path": "metadata.tags", "value": [1, 2]},
{"action": "set", "path": "metadata.obj", "value": {"a": 1}},
],
)
assert result == {"metadata": {"tags": [1, 2], "obj": {"a": 1}}}
def test_does_not_mutate_original_body(self) -> None:
body = {"a": {"b": 1}}
result = apply_body_rules(body, [{"action": "set", "path": "a.c", "value": 2}])
assert result == {"a": {"b": 1, "c": 2}}
assert body == {"a": {"b": 1}}
class TestSetWithOriginalPlaceholder:
"""set 操作中 {{$original}} 占位符的测试"""
def test_wrap_string_in_object(self) -> None:
"""核心用例:字符串值包裹成对象结构"""
body = {"para": "text"}
result = apply_body_rules(
body,
[{"action": "set", "path": "para", "value": [{"text": "{{$original}}"}]}],
)
assert result == {"para": [{"text": "text"}]}
def test_exact_placeholder_preserves_number(self) -> None:
"""完全匹配占位符时保留原始类型: number"""
body = {"count": 42}
result = apply_body_rules(
body,
[{"action": "set", "path": "count", "value": {"num": "{{$original}}"}}],
)
assert result == {"count": {"num": 42}}
assert isinstance(result["count"]["num"], int)
def test_exact_placeholder_preserves_dict(self) -> None:
"""完全匹配占位符时保留原始类型: dict"""
body = {"data": {"key": "val"}}
result = apply_body_rules(
body,
[{"action": "set", "path": "data", "value": {"wrapped": "{{$original}}"}}],
)
assert result == {"data": {"wrapped": {"key": "val"}}}
def test_exact_placeholder_preserves_list(self) -> None:
"""完全匹配占位符时保留原始类型: list"""
body = {"items": [1, 2, 3]}
result = apply_body_rules(
body,
[{"action": "set", "path": "items", "value": {"arr": "{{$original}}"}}],
)
assert result == {"items": {"arr": [1, 2, 3]}}
def test_partial_placeholder_converts_to_string(self) -> None:
"""部分匹配时将原值转为 str 拼接"""
body = {"name": "world"}
result = apply_body_rules(
body,
[{"action": "set", "path": "name", "value": "hello_{{$original}}_suffix"}],
)
assert result == {"name": "hello_world_suffix"}
def test_partial_placeholder_with_number(self) -> None:
"""部分匹配 + 非字符串原值: 数字转 str"""
body = {"ver": 3}
result = apply_body_rules(
body,
[{"action": "set", "path": "ver", "value": "version_{{$original}}"}],
)
assert result == {"ver": "version_3"}
def test_no_placeholder_acts_like_plain_set(self) -> None:
"""不含占位符时行为与原 set 完全一致"""
body = {"a": 1}
result = apply_body_rules(
body,
[{"action": "set", "path": "a", "value": {"new": "val"}}],
)
assert result == {"a": {"new": "val"}}
def test_missing_path_uses_none(self) -> None:
"""路径不存在时 original 为 None"""
body: dict[str, Any] = {}
result = apply_body_rules(
body,
[{"action": "set", "path": "missing", "value": {"was": "{{$original}}"}}],
)
assert result == {"missing": {"was": None}}
def test_nested_path(self) -> None:
"""嵌套路径"""
body = {"a": {"b": "original"}}
result = apply_body_rules(
body,
[{"action": "set", "path": "a.b", "value": [{"content": "{{$original}}"}]}],
)
assert result == {"a": {"b": [{"content": "original"}]}}
def test_original_placeholder_updates_top_level_field(self) -> None:
"""顶层字段同样支持 {{$original}} 占位符更新"""
body = {"model": "gpt-4", "other": "val"}
result = apply_body_rules(
body,
[{"action": "set", "path": "model", "value": "{{$original}}_modified"}],
)
assert result["model"] == "gpt-4_modified"
def test_does_not_mutate_original(self) -> None:
"""不修改原始 body"""
body = {"x": "original"}
result = apply_body_rules(
body,
[{"action": "set", "path": "x", "value": {"wrapped": "{{$original}}"}}],
)
assert result == {"x": {"wrapped": "original"}}
assert body == {"x": "original"}
def test_multiple_placeholders_in_one_string(self) -> None:
"""一个字符串中多个占位符"""
body = {"val": "X"}
result = apply_body_rules(
body,
[{"action": "set", "path": "val", "value": "{{$original}}-{{$original}}"}],
)
assert result == {"val": "X-X"}
def test_deeply_nested_template(self) -> None:
"""深层嵌套模板"""
body = {"data": "hello"}
result = apply_body_rules(
body,
[{"action": "set", "path": "data", "value": {"a": {"b": [{"c": "{{$original}}"}]}}}],
)
assert result == {"data": {"a": {"b": [{"c": "hello"}]}}}
class TestConditionalBodyRules:
"""条件触发 body_rules 的测试"""
# ---- 向后兼容 ----
def test_no_condition_always_executes(self) -> None:
"""无 condition 字段的规则无条件执行"""
body = {"a": 1}
result = apply_body_rules(body, [{"action": "set", "path": "b", "value": 2}])
assert result == {"a": 1, "b": 2}
def test_condition_none_always_executes(self) -> None:
"""condition 为 None 时无条件执行"""
body = {"a": 1}
result = apply_body_rules(
body, [{"action": "set", "path": "b", "value": 2, "condition": None}]
)
assert result == {"a": 1, "b": 2}
# ---- 无效 condition -> 跳过规则 (fail-closed) ----
def test_invalid_condition_not_dict_skips(self) -> None:
body = {"a": 1}
result = apply_body_rules(
body, [{"action": "set", "path": "b", "value": 2, "condition": "bad"}]
)
assert result == {"a": 1}
def test_invalid_condition_missing_op_skips(self) -> None:
body = {"a": 1}
result = apply_body_rules(
body, [{"action": "set", "path": "b", "value": 2, "condition": {"path": "a"}}]
)
assert result == {"a": 1}
def test_invalid_condition_missing_path_skips(self) -> None:
body = {"a": 1}
result = apply_body_rules(
body,
[{"action": "set", "path": "b", "value": 2, "condition": {"op": "eq", "value": 1}}],
)
assert result == {"a": 1}
def test_invalid_condition_unknown_op_skips(self) -> None:
body = {"a": 1}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "b",
"value": 2,
"condition": {"path": "a", "op": "like", "value": 1},
}
],
)
assert result == {"a": 1}
# ---- eq / neq ----
def test_eq_match(self) -> None:
body = {"model": "claude-3"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "temp",
"value": 0.5,
"condition": {"path": "model", "op": "eq", "value": "claude-3"},
}
],
)
assert result["temp"] == 0.5
def test_eq_no_match(self) -> None:
body = {"model": "gpt-4"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "temp",
"value": 0.5,
"condition": {"path": "model", "op": "eq", "value": "claude-3"},
}
],
)
assert "temp" not in result
def test_neq_match(self) -> None:
body = {"model": "gpt-4"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "temp",
"value": 0.5,
"condition": {"path": "model", "op": "neq", "value": "claude-3"},
}
],
)
assert result["temp"] == 0.5
def test_neq_no_match(self) -> None:
body = {"model": "claude-3"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "temp",
"value": 0.5,
"condition": {"path": "model", "op": "neq", "value": "claude-3"},
}
],
)
assert "temp" not in result
# ---- gt / lt / gte / lte ----
def test_gt_match(self) -> None:
body = {"score": 80}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "passed",
"value": True,
"condition": {"path": "score", "op": "gt", "value": 60},
}
],
)
assert result["passed"] is True
def test_gt_no_match(self) -> None:
body = {"score": 60}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "passed",
"value": True,
"condition": {"path": "score", "op": "gt", "value": 60},
}
],
)
assert "passed" not in result
def test_lt_match(self) -> None:
body = {"temp": 0.3}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "low",
"value": True,
"condition": {"path": "temp", "op": "lt", "value": 0.5},
}
],
)
assert result["low"] is True
def test_gte_match_equal(self) -> None:
body = {"count": 10}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "count", "op": "gte", "value": 10},
}
],
)
assert result["ok"] is True
def test_lte_match(self) -> None:
body = {"count": 5}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "count", "op": "lte", "value": 5},
}
],
)
assert result["ok"] is True
def test_numeric_op_on_non_numeric_returns_false(self) -> None:
body = {"val": "hello"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "val", "op": "gt", "value": 0},
}
],
)
assert "ok" not in result
# ---- starts_with / ends_with ----
def test_starts_with_match(self) -> None:
body = {"model": "claude-3-opus"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "provider",
"value": "anthropic",
"condition": {"path": "model", "op": "starts_with", "value": "claude"},
}
],
)
assert result["provider"] == "anthropic"
def test_starts_with_no_match(self) -> None:
body = {"model": "gpt-4"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "provider",
"value": "anthropic",
"condition": {"path": "model", "op": "starts_with", "value": "claude"},
}
],
)
assert "provider" not in result
def test_ends_with_match(self) -> None:
body = {"model": "claude-3-opus"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "tier",
"value": "top",
"condition": {"path": "model", "op": "ends_with", "value": "opus"},
}
],
)
assert result["tier"] == "top"
def test_starts_with_on_non_string_returns_false(self) -> None:
body = {"val": 123}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "val", "op": "starts_with", "value": "1"},
}
],
)
assert "ok" not in result
# ---- contains ----
def test_contains_string_match(self) -> None:
body = {"prompt": "hello world"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "found",
"value": True,
"condition": {"path": "prompt", "op": "contains", "value": "world"},
}
],
)
assert result["found"] is True
def test_contains_array_match(self) -> None:
body = {"tags": ["a", "b", "c"]}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "found",
"value": True,
"condition": {"path": "tags", "op": "contains", "value": "b"},
}
],
)
assert result["found"] is True
def test_contains_array_no_match(self) -> None:
body = {"tags": ["a", "b"]}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "found",
"value": True,
"condition": {"path": "tags", "op": "contains", "value": "z"},
}
],
)
assert "found" not in result
# ---- matches (regex) ----
def test_matches_regex_match(self) -> None:
body = {"model": "claude-3.5-sonnet"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "matched",
"value": True,
"condition": {"path": "model", "op": "matches", "value": r"claude-\d+"},
}
],
)
assert result["matched"] is True
def test_matches_regex_no_match(self) -> None:
body = {"model": "gpt-4o"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "matched",
"value": True,
"condition": {"path": "model", "op": "matches", "value": r"^claude"},
}
],
)
assert "matched" not in result
def test_matches_invalid_regex_returns_false(self) -> None:
body = {"val": "test"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "val", "op": "matches", "value": "[invalid"},
}
],
)
assert "ok" not in result
# ---- exists / not_exists ----
def test_exists_match(self) -> None:
body = {"metadata": {"key": "val"}}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "has_meta",
"value": True,
"condition": {"path": "metadata", "op": "exists"},
}
],
)
assert result["has_meta"] is True
def test_exists_no_match(self) -> None:
body = {"a": 1}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "has_meta",
"value": True,
"condition": {"path": "metadata", "op": "exists"},
}
],
)
assert "has_meta" not in result
def test_not_exists_match(self) -> None:
body = {"a": 1}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "metadata",
"value": {},
"condition": {"path": "metadata", "op": "not_exists"},
}
],
)
assert result["metadata"] == {}
def test_not_exists_no_match(self) -> None:
body = {"metadata": "exists"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "created",
"value": True,
"condition": {"path": "metadata", "op": "not_exists"},
}
],
)
assert "created" not in result
# ---- in ----
def test_in_match(self) -> None:
body = {"model": "claude-3"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "supported",
"value": True,
"condition": {
"path": "model",
"op": "in",
"value": ["claude-3", "claude-3.5", "gpt-4"],
},
}
],
)
assert result["supported"] is True
def test_in_no_match(self) -> None:
body = {"model": "gemini-pro"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "supported",
"value": True,
"condition": {"path": "model", "op": "in", "value": ["claude-3", "gpt-4"]},
}
],
)
assert "supported" not in result
def test_in_non_list_value_returns_false(self) -> None:
body = {"model": "claude"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "model", "op": "in", "value": "claude"},
}
],
)
assert "ok" not in result
# ---- type_is ----
def test_type_is_string(self) -> None:
body = {"val": "hello"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "val", "op": "type_is", "value": "string"},
}
],
)
assert result["ok"] is True
def test_type_is_number_excludes_bool(self) -> None:
body = {"val": True}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "val", "op": "type_is", "value": "number"},
}
],
)
assert "ok" not in result
def test_type_is_number_int(self) -> None:
body = {"val": 42}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "val", "op": "type_is", "value": "number"},
}
],
)
assert result["ok"] is True
def test_type_is_boolean(self) -> None:
body = {"val": False}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "val", "op": "type_is", "value": "boolean"},
}
],
)
assert result["ok"] is True
def test_type_is_array(self) -> None:
body = {"val": [1, 2]}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "val", "op": "type_is", "value": "array"},
}
],
)
assert result["ok"] is True
def test_type_is_object(self) -> None:
body = {"val": {"a": 1}}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "val", "op": "type_is", "value": "object"},
}
],
)
assert result["ok"] is True
def test_type_is_null(self) -> None:
body = {"val": None}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "val", "op": "type_is", "value": "null"},
}
],
)
assert result["ok"] is True
def test_type_is_invalid_type_name(self) -> None:
body = {"val": "hello"}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "ok",
"value": True,
"condition": {"path": "val", "op": "type_is", "value": "str"},
}
],
)
assert "ok" not in result
# ---- 链式触发 ----
def test_chain_second_rule_sees_first_rule_changes(self) -> None:
"""第二条规则的 condition 评估的是第一条规则修改后的 body"""
body: dict[str, Any] = {"a": 1}
result = apply_body_rules(
body,
[
# 规则 1: 无条件创建 metadata
{"action": "set", "path": "metadata", "value": {}},
# 规则 2: 仅当 metadata 存在且是 object 时设置子字段
{
"action": "set",
"path": "metadata.gateway",
"value": "aether",
"condition": {"path": "metadata", "op": "type_is", "value": "object"},
},
],
)
assert result == {"a": 1, "metadata": {"gateway": "aether"}}
def test_chain_condition_on_previously_set_value(self) -> None:
"""条件引用前序规则 set 的值"""
body: dict[str, Any] = {}
result = apply_body_rules(
body,
[
# 规则 1: 创建标记
{"action": "set", "path": "flag", "value": "enabled"},
# 规则 2: 当 flag == "enabled" 时设置
{
"action": "set",
"path": "extra",
"value": 42,
"condition": {"path": "flag", "op": "eq", "value": "enabled"},
},
],
)
assert result == {"flag": "enabled", "extra": 42}
def test_chain_not_exists_then_set(self) -> None:
"""经典链式模式: not_exists 创建 → 后续规则 condition 检测已创建"""
body: dict[str, Any] = {}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "metadata",
"value": {},
"condition": {"path": "metadata", "op": "not_exists"},
},
{
"action": "set",
"path": "metadata.source",
"value": "api",
"condition": {"path": "metadata", "op": "exists"},
},
],
)
assert result == {"metadata": {"source": "api"}}
def test_chain_skipped_rule_does_not_affect_subsequent(self) -> None:
"""被跳过的规则不影响后续规则的 condition 评估"""
body = {"x": 1}
result = apply_body_rules(
body,
[
# 规则 1: 条件不满足,跳过
{
"action": "set",
"path": "y",
"value": 2,
"condition": {"path": "x", "op": "eq", "value": 999},
},
# 规则 2: y 不存在(因为规则 1 被跳过了)
{
"action": "set",
"path": "z",
"value": 3,
"condition": {"path": "y", "op": "not_exists"},
},
],
)
assert "y" not in result
assert result["z"] == 3
# ---- 条件与其他 action 类型配合 ----
def test_condition_with_drop_action(self) -> None:
body = {"temp": 0.5, "model": "claude-3"}
result = apply_body_rules(
body,
[
{
"action": "drop",
"path": "temp",
"condition": {"path": "model", "op": "starts_with", "value": "claude"},
}
],
)
assert "temp" not in result
def test_condition_with_rename_action(self) -> None:
body = {"old_key": "value", "model": "gpt-4"}
result = apply_body_rules(
body,
[
{
"action": "rename",
"from": "old_key",
"to": "new_key",
"condition": {"path": "model", "op": "starts_with", "value": "gpt"},
}
],
)
assert "old_key" not in result
assert result["new_key"] == "value"
def test_condition_prevents_rename(self) -> None:
body = {"old_key": "value", "model": "claude-3"}
result = apply_body_rules(
body,
[
{
"action": "rename",
"from": "old_key",
"to": "new_key",
"condition": {"path": "model", "op": "starts_with", "value": "gpt"},
}
],
)
assert result["old_key"] == "value"
assert "new_key" not in result
# ---- 嵌套路径条件 ----
def test_condition_on_nested_path(self) -> None:
body = {"config": {"mode": "advanced"}, "extra": 1}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "feature",
"value": True,
"condition": {"path": "config.mode", "op": "eq", "value": "advanced"},
}
],
)
assert result["feature"] is True
def test_condition_on_missing_nested_path(self) -> None:
body: dict[str, Any] = {"config": {}}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "feature",
"value": True,
"condition": {"path": "config.mode", "op": "eq", "value": "advanced"},
}
],
)
assert "feature" not in result
class TestWildcardPaths:
"""通配符路径 [*] 和范围 [N-M] 的测试"""
def test_wildcard_set_all_elements(self) -> None:
body = {"tools": [{"name": "a"}, {"name": "b"}, {"name": "c"}]}
result = apply_body_rules(
body,
[{"action": "set", "path": "tools[*].enabled", "value": True}],
)
assert all(t["enabled"] is True for t in result["tools"])
def test_wildcard_regex_replace_all(self) -> None:
body = {"tools": [{"name": "get_user"}, {"name": "get_order"}, {"name": "set_config"}]}
result = apply_body_rules(
body,
[
{
"action": "regex_replace",
"path": "tools[*].name",
"pattern": "^get_",
"replacement": "fetch_",
}
],
)
assert result["tools"][0]["name"] == "fetch_user"
assert result["tools"][1]["name"] == "fetch_order"
assert result["tools"][2]["name"] == "set_config"
def test_wildcard_drop_all(self) -> None:
body = {"items": [{"a": 1, "b": 2}, {"a": 3, "b": 4}]}
result = apply_body_rules(
body,
[{"action": "drop", "path": "items[*].b"}],
)
assert result == {"items": [{"a": 1}, {"a": 3}]}
def test_wildcard_set_with_original_placeholder(self) -> None:
body = {"tools": [{"name": "foo"}, {"name": "bar"}]}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "tools[*].name",
"value": "prefix_{{$original}}",
}
],
)
assert result["tools"][0]["name"] == "prefix_foo"
assert result["tools"][1]["name"] == "prefix_bar"
def test_range_set_partial(self) -> None:
body = {"items": [{"v": 0}, {"v": 1}, {"v": 2}, {"v": 3}, {"v": 4}]}
result = apply_body_rules(
body,
[{"action": "set", "path": "items[1-3].v", "value": 99}],
)
assert result["items"][0]["v"] == 0
assert result["items"][1]["v"] == 99
assert result["items"][2]["v"] == 99
assert result["items"][3]["v"] == 99
assert result["items"][4]["v"] == 4
def test_range_exceeds_array_length(self) -> None:
body = {"items": [{"v": 0}, {"v": 1}]}
result = apply_body_rules(
body,
[{"action": "set", "path": "items[0-10].v", "value": 99}],
)
assert result["items"][0]["v"] == 99
assert result["items"][1]["v"] == 99
def test_wildcard_on_empty_array(self) -> None:
body: dict[str, Any] = {"tools": []}
result = apply_body_rules(
body,
[{"action": "set", "path": "tools[*].name", "value": "x"}],
)
assert result == {"tools": []}
def test_wildcard_on_non_array(self) -> None:
body = {"tools": "not_an_array"}
result = apply_body_rules(
body,
[{"action": "set", "path": "tools[*].name", "value": "x"}],
)
assert result == {"tools": "not_an_array"}
def test_wildcard_nested(self) -> None:
body = {
"data": [
{"items": [{"name": "a"}, {"name": "b"}]},
{"items": [{"name": "c"}]},
]
}
result = apply_body_rules(
body,
[{"action": "set", "path": "data[*].items[*].name", "value": "x"}],
)
assert result["data"][0]["items"][0]["name"] == "x"
assert result["data"][0]["items"][1]["name"] == "x"
assert result["data"][1]["items"][0]["name"] == "x"
def test_wildcard_append(self) -> None:
body = {"groups": [{"tags": ["a"]}, {"tags": ["b"]}]}
result = apply_body_rules(
body,
[{"action": "append", "path": "groups[*].tags", "value": "new"}],
)
assert result["groups"][0]["tags"] == ["a", "new"]
assert result["groups"][1]["tags"] == ["b", "new"]
def test_rename_with_wildcard_is_skipped(self) -> None:
"""rename 不支持通配符,应跳过"""
body = {"items": [{"old": 1}, {"old": 2}]}
result = apply_body_rules(
body,
[{"action": "rename", "from": "items[*].old", "to": "items[*].new"}],
)
assert result == {"items": [{"old": 1}, {"old": 2}]}
def test_wildcard_with_condition(self) -> None:
body = {"flag": True, "tools": [{"name": "a"}, {"name": "b"}]}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "tools[*].active",
"value": True,
"condition": {"path": "flag", "op": "eq", "value": True},
}
],
)
assert result["tools"][0]["active"] is True
assert result["tools"][1]["active"] is True
def test_does_not_mutate_original(self) -> None:
body = {"tools": [{"name": "a"}, {"name": "b"}]}
result = apply_body_rules(
body,
[{"action": "set", "path": "tools[*].name", "value": "x"}],
)
assert result["tools"][0]["name"] == "x"
assert body["tools"][0]["name"] == "a"
class TestNameStyleAction:
"""name_style action 的测试"""
def test_snake_case(self) -> None:
body = {"tools": [{"name": "getUserInfo"}, {"name": "setOrderStatus"}]}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tools[*].name", "style": "snake_case"}],
)
assert result["tools"][0]["name"] == "get_user_info"
assert result["tools"][1]["name"] == "set_order_status"
def test_camel_case(self) -> None:
body = {"tools": [{"name": "get_user_info"}, {"name": "set_order_status"}]}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tools[*].name", "style": "camelCase"}],
)
assert result["tools"][0]["name"] == "getUserInfo"
assert result["tools"][1]["name"] == "setOrderStatus"
def test_pascal_case(self) -> None:
body = {"tools": [{"name": "get_user_info"}]}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tools[*].name", "style": "PascalCase"}],
)
assert result["tools"][0]["name"] == "GetUserInfo"
def test_kebab_case(self) -> None:
body = {"tools": [{"name": "getUserInfo"}]}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tools[*].name", "style": "kebab-case"}],
)
assert result["tools"][0]["name"] == "get-user-info"
def test_single_path_no_wildcard(self) -> None:
body = {"tool": {"name": "myFunctionName"}}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tool.name", "style": "snake_case"}],
)
assert result["tool"]["name"] == "my_function_name"
def test_invalid_style_skipped(self) -> None:
body = {"tools": [{"name": "foo"}]}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tools[0].name", "style": "UPPER_CASE"}],
)
assert result["tools"][0]["name"] == "foo"
def test_non_string_value_skipped(self) -> None:
body = {"tools": [{"name": 123}]}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tools[0].name", "style": "snake_case"}],
)
assert result["tools"][0]["name"] == 123
def test_already_correct_style(self) -> None:
body = {"tools": [{"name": "already_snake_case"}]}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tools[0].name", "style": "snake_case"}],
)
assert result["tools"][0]["name"] == "already_snake_case"
def test_mixed_styles_in_array(self) -> None:
body = {
"tools": [
{"name": "getUserInfo"},
{"name": "set_order_status"},
{"name": "DeleteItem"},
]
}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tools[*].name", "style": "snake_case"}],
)
assert result["tools"][0]["name"] == "get_user_info"
assert result["tools"][1]["name"] == "set_order_status"
assert result["tools"][2]["name"] == "delete_item"
def test_with_numbers_in_name(self) -> None:
body = {"tools": [{"name": "getV2User"}]}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tools[0].name", "style": "snake_case"}],
)
assert result["tools"][0]["name"] == "get_v_2_user"
def test_does_not_mutate_original(self) -> None:
body = {"tools": [{"name": "getUserInfo"}]}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tools[0].name", "style": "snake_case"}],
)
assert result["tools"][0]["name"] == "get_user_info"
assert body["tools"][0]["name"] == "getUserInfo"
def test_capitalize(self) -> None:
body = {"tools": [{"name": "writer"}, {"name": "edit"}]}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tools[*].name", "style": "capitalize"}],
)
assert result["tools"][0]["name"] == "Writer"
assert result["tools"][1]["name"] == "Edit"
def test_capitalize_preserves_rest(self) -> None:
"""capitalize 只改首字母,保留其余部分"""
body = {"tools": [{"name": "getUserInfo"}]}
result = apply_body_rules(
body,
[{"action": "name_style", "path": "tools[0].name", "style": "capitalize"}],
)
assert result["tools"][0]["name"] == "GetUserInfo"
class TestItemCondition:
"""$item 条件引用的测试 -- 通配符路径下逐元素评估"""
def test_name_style_with_item_condition(self) -> None:
"""只对 name 在列表中的 tool 做首字母大写"""
body = {
"tools": [
{"name": "writer"},
{"name": "edit"},
{"name": "search"},
]
}
result = apply_body_rules(
body,
[
{
"action": "name_style",
"path": "tools[*].name",
"style": "capitalize",
"condition": {
"path": "$item.name",
"op": "in",
"value": ["writer", "edit"],
},
}
],
)
assert result["tools"][0]["name"] == "Writer"
assert result["tools"][1]["name"] == "Edit"
assert result["tools"][2]["name"] == "search" # 不在列表中,不变
def test_set_with_item_condition(self) -> None:
"""set + $item condition"""
body = {"items": [{"type": "a", "v": 1}, {"type": "b", "v": 2}, {"type": "a", "v": 3}]}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "items[*].v",
"value": 99,
"condition": {"path": "$item.type", "op": "eq", "value": "a"},
}
],
)
assert result["items"][0]["v"] == 99
assert result["items"][1]["v"] == 2 # type=b, 不变
assert result["items"][2]["v"] == 99
def test_drop_with_item_condition(self) -> None:
"""drop + $item condition"""
body = {
"tools": [
{"name": "a", "extra": 1},
{"name": "b", "extra": 2},
{"name": "c", "extra": 3},
]
}
result = apply_body_rules(
body,
[
{
"action": "drop",
"path": "tools[*].extra",
"condition": {"path": "$item.name", "op": "eq", "value": "b"},
}
],
)
assert "extra" in result["tools"][0]
assert "extra" not in result["tools"][1] # name=b, extra 被删除
assert "extra" in result["tools"][2]
def test_regex_replace_with_item_condition(self) -> None:
"""regex_replace + $item condition"""
body = {
"tools": [
{"name": "get_user", "type": "read"},
{"name": "set_user", "type": "write"},
]
}
result = apply_body_rules(
body,
[
{
"action": "regex_replace",
"path": "tools[*].name",
"pattern": "^get_",
"replacement": "fetch_",
"condition": {"path": "$item.type", "op": "eq", "value": "read"},
}
],
)
assert result["tools"][0]["name"] == "fetch_user"
assert result["tools"][1]["name"] == "set_user" # type=write, 不变
def test_item_condition_with_exists(self) -> None:
"""$item.xxx + exists"""
body = {"items": [{"name": "a"}, {"name": "b", "flag": True}, {"name": "c"}]}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "items[*].marked",
"value": True,
"condition": {"path": "$item.flag", "op": "exists"},
}
],
)
assert "marked" not in result["items"][0]
assert result["items"][1]["marked"] is True
assert "marked" not in result["items"][2]
def test_item_exact_ref(self) -> None:
"""$item (不带后缀) 引用整个元素"""
body = {"items": ["hello", 42, "world"]}
result = apply_body_rules(
body,
[
{
"action": "regex_replace",
"path": "items[*]",
"pattern": "^hello$",
"replacement": "hi",
"condition": {"path": "$item", "op": "type_is", "value": "string"},
}
],
)
assert result["items"][0] == "hi"
assert result["items"][1] == 42 # 不是 string跳过
assert result["items"][2] == "world"
def test_non_item_condition_still_global(self) -> None:
"""不含 $item 的 condition 仍然全局评估"""
body = {"flag": False, "tools": [{"name": "a"}, {"name": "b"}]}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "tools[*].active",
"value": True,
"condition": {"path": "flag", "op": "eq", "value": True},
}
],
)
# flag=False全局条件不满足所有元素都不变
assert "active" not in result["tools"][0]
assert "active" not in result["tools"][1]
def test_nested_all_any_condition_with_item_ref(self) -> None:
"""嵌套 all/any 中包含 $item 时,按元素递归评估。"""
body = {
"flag": True,
"tools": [
{"name": "a", "type": "read"},
{"name": "b", "type": "write"},
{"name": "c", "type": "other"},
],
}
result = apply_body_rules(
body,
[
{
"action": "set",
"path": "tools[*].enabled",
"value": True,
"condition": {
"all": [
{"path": "flag", "op": "eq", "value": True},
{
"any": [
{"path": "$item.type", "op": "eq", "value": "read"},
{"path": "$item.type", "op": "eq", "value": "write"},
]
},
]
},
}
],
)
assert result["tools"][0]["enabled"] is True
assert result["tools"][1]["enabled"] is True
assert "enabled" not in result["tools"][2]
def test_condition_source_original_uses_original_body_after_current_mutation(self) -> None:
"""source=original 在前序规则改写 current body 后仍读取原始请求体。"""
original_body = {"metadata": {"mode": "prod"}}
result = apply_body_rules(
original_body,
[
{"action": "set", "path": "metadata.mode", "value": "test"},
{
"action": "set",
"path": "audit.from_original",
"value": True,
"condition": {
"path": "metadata.mode",
"op": "eq",
"value": "prod",
"source": "original",
},
},
{
"action": "set",
"path": "audit.from_current",
"value": True,
"condition": {
"path": "metadata.mode",
"op": "eq",
"value": "prod",
},
},
],
original_body=original_body,
)
assert result["metadata"]["mode"] == "test"
assert result["audit"]["from_original"] is True
assert "from_current" not in result["audit"]
def test_condition_all_any_can_mix_original_and_current_sources(self) -> None:
"""组合条件允许 current/original 混用。"""
original_body = {"mode": "prod", "count": 0}
result = apply_body_rules(
original_body,
[
{"action": "set", "path": "count", "value": 3},
{
"action": "set",
"path": "matched",
"value": True,
"condition": {
"all": [
{"path": "count", "op": "gte", "value": 1},
{
"any": [
{
"path": "mode",
"op": "eq",
"value": "prod",
"source": "original",
},
{"path": "mode", "op": "eq", "value": "stage"},
]
},
]
},
},
],
original_body=original_body,
)
assert result["matched"] is True
class TestPromptFieldMutations:
def test_openai_cli_prompt_fields_can_be_updated(self) -> None:
body = {
"model": "gpt-5-codex",
"input": [{"role": "user", "content": "hi"}],
}
result = apply_body_rules(
body,
[
{"action": "set", "path": "instructions", "value": "You are GPT-5."},
{"action": "set", "path": "input[0].content", "value": "patched"},
{"action": "set", "path": "prompt_cache_key", "value": "blocked"},
],
)
assert result["instructions"] == "You are GPT-5."
assert result["input"][0]["content"] == "patched"
assert result["prompt_cache_key"] == "blocked"
def test_gemini_camelcase_alias_prompt_fields_can_be_updated(self) -> None:
body = {
"contents": [{"role": "user", "parts": [{"text": "hi"}]}],
"systemInstruction": {"parts": [{"text": "system"}]},
"toolConfig": {"functionCallingConfig": {"mode": "AUTO"}},
"generationConfig": {"temperature": 0.1},
"metadata": {"safe": True},
}
result = apply_body_rules(
body,
[
{"action": "set", "path": "systemInstruction.parts[0].text", "value": "mutated"},
{"action": "drop", "path": "toolConfig"},
{"action": "rename", "from": "generationConfig", "to": "generation_config"},
{"action": "append", "path": "contents", "value": {"role": "model", "parts": []}},
{
"action": "insert",
"path": "contents",
"index": 0,
"value": {"role": "user", "parts": [{"text": "preface"}]},
},
{"action": "set", "path": "metadata.safe", "value": False},
],
)
assert result["contents"] == [
{"role": "user", "parts": [{"text": "preface"}]},
{"role": "user", "parts": [{"text": "hi"}]},
{"role": "model", "parts": []},
]
assert result["systemInstruction"] == {"parts": [{"text": "mutated"}]}
assert "toolConfig" not in result
assert "generationConfig" not in result
assert result["generation_config"] == {"temperature": 0.1}
assert result["metadata"]["safe"] is False
def test_openai_prompt_fields_allow_all_mutating_actions(self) -> None:
body = {
"messages": [{"role": "user", "content": "hi"}],
"tools": [{"name": "ReadFile"}],
"tool_choice": {"type": "function", "function": {"name": "ReadFile"}},
"metadata": {"safe": True},
}
result = apply_body_rules(
body,
[
{"action": "set", "path": "messages", "value": []},
{"action": "drop", "path": "tools"},
{"action": "rename", "from": "tool_choice", "to": "choice"},
{
"action": "append",
"path": "messages",
"value": {"role": "assistant", "content": "x"},
},
{
"action": "insert",
"path": "messages",
"index": 0,
"value": {"role": "system", "content": "x"},
},
{
"action": "regex_replace",
"path": "tools[0].name",
"pattern": "Read",
"replacement": "Write",
},
{"action": "name_style", "path": "tools[*].name", "style": "snake_case"},
{"action": "set", "path": "metadata.safe", "value": False},
],
)
assert result["messages"] == [
{"role": "system", "content": "x"},
{"role": "assistant", "content": "x"},
]
assert "tools" not in result
assert "tool_choice" not in result
assert result["choice"] == {"type": "function", "function": {"name": "ReadFile"}}
assert result["metadata"]["safe"] is False