fix: delete agent 500 error + dynamic personality + deployment guide
- Fix delete agent 500: clean up FK records (agent_llm_logs, permissions, schedules, executions, team_members) and unbind goals/tasks before delete - Remove hardcoded personality templates in Android, replace with dynamic system prompt generation from name + description - Set promptSectionsEnabled=false to bypass PromptComposer for personality - Add Tencent Cloud Linux deployment guide (Docker Compose) - Accumulated backend service updates, frontend UI fixes, Android app changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -263,8 +263,8 @@ class TestToolRegistryExecute:
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
async def test_execute_builtin(self, registry):
|
||||
def hello(**kwargs):
|
||||
return f"Hello, {kwargs.get('name', 'world')}!"
|
||||
def hello(name="world"):
|
||||
return f"Hello, {name}!"
|
||||
|
||||
registry.register_builtin_tool("hello", hello, {"function": {"name": "hello"}})
|
||||
result = await registry.execute_tool("hello", {"name": "Test"})
|
||||
@@ -291,3 +291,98 @@ class TestToolRegistryExecute:
|
||||
registry._custom_tool_configs["wf"] = config
|
||||
result = await registry.execute_tool("wf", {})
|
||||
assert "暂不支持" in result
|
||||
|
||||
|
||||
class TestToolRegistryParameterFiltering:
|
||||
"""工具参数过滤测试 —— LLM 生成错误参数名 → 过滤 → 正常执行"""
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
async def test_unknown_params_filtered(self, registry):
|
||||
"""未知参数被过滤,工具正常执行"""
|
||||
def greet(name="world"):
|
||||
return f"Hello, {name}!"
|
||||
|
||||
registry.register_builtin_tool("greet", greet, {"function": {"name": "greet"}})
|
||||
# LLM 生成了未知参数 extra_field
|
||||
result = await registry._run_function(greet, "greet", {
|
||||
"name": "Test", "extra_field": "should_be_filtered"
|
||||
})
|
||||
assert "Hello, Test!" in result
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
async def test_missing_params_use_defaults(self, registry):
|
||||
"""缺少参数时使用函数默认值"""
|
||||
def greet(name="world"):
|
||||
return f"Hello, {name}!"
|
||||
|
||||
registry.register_builtin_tool("greet", greet, {"function": {"name": "greet"}})
|
||||
result = await registry._run_function(greet, "greet", {})
|
||||
assert "Hello, world!" in result
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
async def test_no_valid_params_does_not_crash(self, registry):
|
||||
"""全部参数都无效时不崩溃"""
|
||||
def greet(name="world"):
|
||||
return f"Hello, {name}!"
|
||||
|
||||
registry.register_builtin_tool("greet", greet, {"function": {"name": "greet"}})
|
||||
# 所有参数都不匹配
|
||||
result = await registry._run_function(greet, "greet", {
|
||||
"bad_param_1": 1, "bad_param_2": 2
|
||||
})
|
||||
assert "Hello, world!" in result
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
async def test_mixed_valid_and_invalid_params(self, registry):
|
||||
"""混合有效/无效参数时只使用有效参数"""
|
||||
def calc(x=0, y=0):
|
||||
return str(x + y)
|
||||
|
||||
registry.register_builtin_tool("calc", calc, {"function": {"name": "calc"}})
|
||||
result = await registry._run_function(calc, "calc", {
|
||||
"x": 3, "y": 4, "z": 100, "unused": "ignored"
|
||||
})
|
||||
assert "7" in result
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
async def test_type_coercion_handled_gracefully(self, registry):
|
||||
"""类型不匹配时使用 Python 默认行为"""
|
||||
def add(x=0, y=0):
|
||||
return str(x + y)
|
||||
|
||||
registry.register_builtin_tool("add", add, {"function": {"name": "add"}})
|
||||
# 字符串参数可能导致 TypeError,但不应崩溃
|
||||
result = await registry._run_function(add, "add", {
|
||||
"x": "hello", "y": "world"
|
||||
})
|
||||
# 要么成功(字符串拼接),要么失败但不崩溃
|
||||
assert isinstance(result, str)
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
async def test_empty_args_dict(self, registry):
|
||||
"""空参数字典正常执行"""
|
||||
def status():
|
||||
return "ok"
|
||||
|
||||
registry.register_builtin_tool("status", status, {"function": {"name": "status"}})
|
||||
result = await registry._run_function(status, "status", {})
|
||||
assert "ok" in result
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
async def test_extra_positional_not_in_sig(self, registry):
|
||||
"""参数名不在函数签名中时被过滤"""
|
||||
def read_file(path=""):
|
||||
return f"read: {path}"
|
||||
|
||||
registry.register_builtin_tool("read_file", read_file, {"function": {"name": "read_file"}})
|
||||
result = await registry._run_function(read_file, "read_file", {
|
||||
"path": "/data.txt", "encoding": "utf-8", "mode": "r"
|
||||
})
|
||||
assert "read: /data.txt" in result
|
||||
|
||||
Reference in New Issue
Block a user