test_workspace_guard.py 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. """工作区对话型 agent 必须绑定工作文件夹的后端守卫测试。
  2. 防的是最坑的失败模式:无 ?dir → 静默回退 agent 空家目录 → 读不到用户文件
  3. 还以 completed 收尾(假装成功)。守卫把它变成显式 400 WORKSPACE_DIR_REQUIRED。
  4. """
  5. from __future__ import annotations
  6. import pytest
  7. from fastapi import HTTPException
  8. from agentpaas.api.v1.agents import _require_workspace_dir
  9. class _Req:
  10. def __init__(self, ctx):
  11. self.context = ctx
  12. def test_workspace_assistant_rejects_empty_context():
  13. agent = {"agent_template": "workspace.assistant"}
  14. with pytest.raises(HTTPException) as ei:
  15. _require_workspace_dir(agent, _Req({}))
  16. assert ei.value.status_code == 400
  17. assert ei.value.detail["code"] == "WORKSPACE_DIR_REQUIRED"
  18. def test_workspace_assistant_rejects_nonexistent_dir():
  19. agent = {"agent_template": "workspace.assistant"}
  20. with pytest.raises(HTTPException):
  21. _require_workspace_dir(agent, _Req({"work_dir": "/no/such/dir/zzz_nope"}))
  22. def test_workspace_assistant_accepts_valid_dir(tmp_path):
  23. agent = {"agent_template": "workspace.assistant"}
  24. # 有效目录 → 不抛
  25. _require_workspace_dir(agent, _Req({"work_dir": str(tmp_path)}))
  26. def test_workspace_assistant_rejects_non_dict_context():
  27. agent = {"agent_template": "workspace.assistant"}
  28. with pytest.raises(HTTPException):
  29. _require_workspace_dir(agent, _Req(None))
  30. def test_non_workspace_agent_unaffected():
  31. # 专项智能体不受此守卫约束(它们写各自 run 工作区)
  32. agent = {"agent_template": "research.top-journal-reviewer"}
  33. _require_workspace_dir(agent, _Req({})) # 不抛
  34. _require_workspace_dir({"agent_template": ""}, _Req({})) # 空模板也不抛
  35. from agentpaas.api.v1.agents import _is_native_workspace
  36. def test_native_lane_only_for_claude_code_provider():
  37. ws = {"agent_template": "workspace.assistant"}
  38. assert _is_native_workspace(ws, {"model": {"provider": "claude-code"}}) is True
  39. # 切到 qwen/ollama/openai → 退回 react 车道(native 跑不了非 claude 模型)
  40. assert _is_native_workspace(ws, {"model": {"provider": "dashscope", "name": "qwen-max"}}) is False
  41. assert _is_native_workspace(ws, {"model": {"provider": "ollama"}}) is False
  42. assert _is_native_workspace(ws, {"model": {}}) is False
  43. # 非工作区模板:永不走 native
  44. assert _is_native_workspace({"agent_template": "research.x"},
  45. {"model": {"provider": "claude-code"}}) is False
  46. from agentpaas.api.v1.agents import _resolve_session_cwd
  47. def test_session_cwd_aligns_with_workdir_hint(tmp_path):
  48. """会话 CWD 必须 == [工作目录] 提示(overrides.workspace_path),否则相对写入落错目录
  49. (run_bf2405e28547:literature_map.md 落进 agent 家目录而非本 run 工作区)。"""
  50. F = tmp_path / "user_folder"; F.mkdir()
  51. ws = tmp_path / "run_xxx"; ws.mkdir()
  52. home = tmp_path / "agent_home"; home.mkdir()
  53. # 工作区对话模式:CWD = F
  54. assert _resolve_session_cwd(str(F), str(ws), str(home)) == str(F)
  55. # 专项 agent(无 inplace):CWD = 本 run workspace_path(修复点,原来错误地返回 work_dir)
  56. assert _resolve_session_cwd("", str(ws), str(home)) == str(ws)
  57. # 兜底:无 workspace_path → work_dir
  58. assert _resolve_session_cwd("", "", str(home)) == str(home)
  59. # inplace 无效路径被忽略,退回 workspace_path
  60. assert _resolve_session_cwd("/no/such/dir", str(ws), str(home)) == str(ws)