Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/bjvgukv25842-cmyk_resume-ai.json
T

1 line
56 KiB
JSON

{"repo": "bjvgukv25842-cmyk/resume-ai", "files": {"backend/tests/test_ai_settings.py": {"a839701a134c597c5cf4407e6923ced753021712": {"t": 1785746926.3790655, "n": 14094, "h": "6d2d334c5e1d137d", "c": "\"\"\"AI settings API tests.\"\"\"\n\nfrom types import SimpleNamespace\n\nimport pytest\nfrom httpx import AsyncClient\nfrom sqlalchemy import select\n\nfrom app.models.ai_settings import AISettings\nfrom app.models.company import Company\nfrom app.models.user import User\nfrom app.services.auth_service import AuthService\nfrom tests.conftest import TestSessionLocal\n\n\nasync def create_platform_headers(email: str = \"ops@example.com\", role: str = \"superadmin\") -> dict:\n async with TestSessionLocal() as db:\n company = Company(name=\"Platform Ops\", plan=\"free\", monthly_quota=1000, used_quota=0)\n db.add(company)\n await db.flush()\n admin = User(\n company_id=company.id,\n email=email,\n hashed_password=AuthService._hash_password(\"password123\"),\n name=\"Ops\",\n role=role,\n account_type=\"platform\",\n workspace_type=\"platform\",\n )\n db.add(admin)\n await db.commit()\n token = AuthService(db)._create_token(admin.id)\n return {\"Authorization\": f\"Bearer {token}\"}\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_presets_and_update(client: AsyncClient):\n platform_headers = await create_platform_headers()\n\n presets = await client.get(\"/api/v1/ai-settings/presets\")\n assert presets.status_code == 200\n provider_ids = {item[\"id\"] for item in presets.json()[\"providers\"]}\n expected = {\"openai\", \"qwen\", \"zhipu\", \"deepseek\", \"kimi\", \"minimax\", \"anthropic\", \"techmatch_local_agent\"}\n assert expected.issubset(provider_ids)\n assert \"local_agent\" in presets.json()\n deepseek = next(item for item in presets.json()[\"providers\"] if item[\"id\"] == \"deepseek\")\n deepseek_model_ids = {item[\"id\"] for item in deepseek[\"models\"]}\n assert {\"deepseek-v4-flash\", \"deepseek-v4-pro\"}.issubset(deepseek_model_ids)\n\n invalid_ocr = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"vision_provider_id\": \"deepseek\",\n \"vision_api_base\": \"https://api.deepseek.com\",\n \"vision_model\": \"deepseek-chat\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n bad = await client.put(\"/api/v1/ai-settings\", json=invalid_ocr, headers=platform_headers)\n assert bad.status_code == 422\n\n valid = {\n **invalid_ocr,\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n }\n saved = await client.put(\"/api/v1/ai-settings\", json=valid, headers=platform_headers)\n assert saved.status_code == 200\n body = saved.json()\n assert body[\"provider_id\"] == \"deepseek\"\n assert body[\"vision_model\"] == \"qwen3-vl-flash\"\n assert \"api_key\" not in body\n\n\n@pytest.mark.asyncio\nasync def test_local_agent_status_defaults_without_agent(client: AsyncClient):\n platform_headers = await create_platform_headers()\n response = await client.get(\"/api/v1/ai-settings/local-agent/status\", headers=platform_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"configured\"] is False\n assert body[\"online\"] is False\n assert body[\"service_url\"] == \"http://127.0.0.1:8765/v1\"\n assert body[\"data_boundary\"][\"raw_resumes\"] == \"local_agent\"\n\n\n@pytest.mark.asyncio\nasync def test_local_mode_accepts_local_agent_provider(client: AsyncClient):\n platform_headers = await create_platform_headers()\n payload = {\n \"provider_id\": \"techmatch_local_agent\",\n \"api_base\": \"https://api.deepseek.com\",\n \"parse_model\": \"qwen2.5:7b-instruct\",\n \"analyze_model\": \"qwen2.5:7b-instruct\",\n \"evaluation_model\": \"qwen2.5:7b-instruct\",\n \"vision_provider_id\": \"techmatch_local_agent\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5vl:7b\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"embedding_provider_id\": \"local_sentence_transformers\",\n \"embedding_model\": \"BAAI/bge-small-zh-v1.5\",\n \"local_mode_enabled\": True,\n \"local_service_url\": \"http://127.0.0.1:8765/v1\",\n \"allow_cloud_fallback\": False,\n \"extra_headers\": {\"X-TechMatch-Local-Token\": \"change-me\"},\n }\n saved = await client.put(\"/api/v1/ai-settings\", json=payload, headers=platform_headers)\n assert saved.status_code == 200\n body = saved.json()\n assert body[\"provider_id\"] == \"techmatch_local_agent\"\n assert body[\"local_mode_enabled\"] is True\n assert body[\"local_service_url\"] == \"http://127.0.0.1:8765/v1\"\n assert body[\"allow_cloud_fallback\"] is False\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_rejects_insecure_cloud_url_and_forbidden_headers(client: AsyncClient):\n platform_headers = await create_platform_headers()\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"http://api.deepseek.com\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n insecure = await client.put(\"/api/v1/ai-settings\", json=payload, headers=platform_headers)\n assert insecure.status_code == 422\n\n forbidden_header = await client.put(\n \"/api/v1/ai-settings\",\n json={\n **payload,\n \"api_base\": \"https://api.deepseek.com\",\n \"extra_headers\": {\"Authorization\": \"Bearer leaked\"},\n },\n headers=platform_headers,\n )\n assert forbidden_header.status_code == 422\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_accepts_unlisted_text_model_ids(client: AsyncClient):\n platform_headers = await create_platform_headers()\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com\",\n \"parse_model\": \"deepseek-v4-flash\",\n \"analyze_model\": \"future-deepseek-model\",\n \"evaluation_model\": \"future-deepseek-evaluator\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n response = await client.put(\"/api/v1/ai-settings\", json=payload, headers=platform_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"parse_model\"] == \"deepseek-v4-flash\"\n assert body[\"analyze_model\"] == \"future-deepseek-model\"\n assert body[\"evaluation_model\"] == \"future-deepseek-evaluator\"\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_accepts_unlisted_text_models_for_other_providers(client: AsyncClient):\n platform_headers = await create_platform_headers()\n payload = {\n \"provider_id\": \"qwen\",\n \"api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"parse_model\": \"qwen-future-release\",\n \"analyze_model\": \"qwen-future-pro\",\n \"evaluation_model\": \"qwen-future-evaluator\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n response = await client.put(\"/api/v1/ai-settings\", json=payload, headers=platform_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"provider_id\"] == \"qwen\"\n assert body[\"parse_model\"] == \"qwen-future-release\"\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_update_requires_admin_role(client: AsyncClient):\n platform_member_headers = await create_platform_headers(\"ops-member@example.com\", role=\"member\")\n payload = {\n \"provider_id\": \"qwen\",\n \"api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"parse_model\": \"qwen-plus\",\n \"analyze_model\": \"qwen-plus\",\n \"evaluation_model\": \"qwen-plus\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n\n response = await client.put(\"/api/v1/ai-settings\", json=payload, headers=platform_member_headers)\n\n assert response.status_code == 403\n assert \"需要 admin\" in response.json()[\"detail\"]\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_update_requires_platform_admin(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"qwen\",\n \"api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"parse_model\": \"qwen-plus\",\n \"analyze_model\": \"qwen-plus\",\n \"evaluation_model\": \"qwen-plus\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n\n response = await client.put(\"/api/v1/ai-settings\", json=payload, headers=auth_headers)\n\n assert response.status_code == 403\n assert \"平台运营管理员\" in response.json()[\"detail\"]\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_masks_extra_headers_after_save(client: AsyncClient):\n platform_headers = await create_platform_headers()\n payload = {\n \"provider_id\": \"techmatch_local_agent\",\n \"api_base\": \"https://api.deepseek.com\",\n \"parse_model\": \"qwen2.5:7b-instruct\",\n \"analyze_model\": \"qwen2.5:7b-instruct\",\n \"evaluation_model\": \"qwen2.5:7b-instruct\",\n \"vision_provider_id\": \"techmatch_local_agent\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5vl:7b\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"local_mode_enabled\": True,\n \"local_service_url\": \"http://127.0.0.1:8765/v1\",\n \"allow_cloud_fallback\": False,\n \"extra_headers\": {\"X-TechMatch-Local-Token\": \"secret-local-token\"},\n }\n\n saved = await client.put(\"/api/v1/ai-settings\", json=payload, headers=platform_headers)\n assert saved.status_code == 200\n assert saved.json()[\"extra_headers\"] == {\"X-TechMatch-Local-Token\": \"********\"}\n\n loaded = await client.get(\"/api/v1/ai-settings\", headers=platform_headers)\n assert loaded.status_code == 200\n assert loaded.json()[\"extra_headers\"] == {\"X-TechMatch-Local-Token\": \"********\"}\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_serializes_legacy_null_text_as_defaults(client: AsyncClient):\n platform_headers = await create_platform_headers()\n initial = await client.get(\"/api/v1/ai-settings\", headers=platform_headers)\n assert initial.status_code == 200\n\n async with TestSessionLocal() as db:\n row = (await db.execute(select(AISettings))).scalar_one()\n row.api_base = \"null\"\n row.vision_api_base = \"null\"\n row.local_service_url = \"null\"\n row.parse_model = \"null\"\n row.analyze_model = \"undefined\"\n row.vision_model = \"none\"\n await db.commit()\n\n response = await client.get(\"/api/v1/ai-settings\", headers=platform_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"api_base\"] == \"https://api.deepseek.com\"\n assert body[\"vision_api_base\"] == \"https://dashscope.aliyuncs.com/compatible-mode/v1\"\n assert body[\"local_service_url\"] is None\n assert body[\"parse_model\"] == \"deepseek-v4-flash\"\n assert body[\"analyze_model\"] == \"deepseek-v4-flash\"\n assert body[\"vision_model\"] == \"qwen3-vl-flash\"\n\n\n@pytest.mark.asyncio\nasync def test_text_model_test_ignores_local_agent_routing(\n client: AsyncClient,\n monkeypatch,\n):\n platform_headers = await create_platform_headers()\n captured = {}\n\n async def fake_run(runtime, _client, **kwargs):\n captured[\"runtime\"] = runtime\n captured[\"kwargs\"] = kwargs\n message = SimpleNamespace(content=\"ok\")\n return SimpleNamespace(choices=[SimpleNamespace(message=message)]), runtime\n\n monkeypatch.setattr(\"app.services.ai_settings_service.create_llm_client\", lambda runtime: object())\n monkeypatch.setattr(\"app.services.ai_settings_service.run_chat_completion_with_fallback\", fake_run)\n\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"evaluation_model\": \"deepseek-reasoner\",\n \"api_key\": \"sk-user-text\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"vision_api_key\": \"sk-user-vision\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"local_mode_enabled\": True,\n \"local_service_url\": \"http://127.0.0.1:8765/v1\",\n \"allow_cloud_fallback\": False,\n \"extra_headers\": {},\n }\n response = await client.post(\"/api/v1/ai-settings/test/text\", json=payload, headers=platform_headers)\n assert response.status_code == 200\n\n runtime = captured[\"runtime\"]\n assert runtime.local_mode_enabled is False\n assert runtime.request_origin == \"cloud\"\n assert runtime.api_base == \"https://api.deepseek.com\"\n assert captured[\"kwargs\"][\"model\"] == \"deepseek-chat\"\n assert response.json()[\"metadata\"][\"request_origin\"] == \"cloud\"\n"}, "30a4f61f577d0a2f7ff616f540ed5af102daf531": {"t": 1785769092.9521055, "n": 14094, "h": "6d2d334c5e1d137d", "c": "\"\"\"AI settings API tests.\"\"\"\n\nfrom types import SimpleNamespace\n\nimport pytest\nfrom httpx import AsyncClient\nfrom sqlalchemy import select\n\nfrom app.models.ai_settings import AISettings\nfrom app.models.company import Company\nfrom app.models.user import User\nfrom app.services.auth_service import AuthService\nfrom tests.conftest import TestSessionLocal\n\n\nasync def create_platform_headers(email: str = \"ops@example.com\", role: str = \"superadmin\") -> dict:\n async with TestSessionLocal() as db:\n company = Company(name=\"Platform Ops\", plan=\"free\", monthly_quota=1000, used_quota=0)\n db.add(company)\n await db.flush()\n admin = User(\n company_id=company.id,\n email=email,\n hashed_password=AuthService._hash_password(\"password123\"),\n name=\"Ops\",\n role=role,\n account_type=\"platform\",\n workspace_type=\"platform\",\n )\n db.add(admin)\n await db.commit()\n token = AuthService(db)._create_token(admin.id)\n return {\"Authorization\": f\"Bearer {token}\"}\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_presets_and_update(client: AsyncClient):\n platform_headers = await create_platform_headers()\n\n presets = await client.get(\"/api/v1/ai-settings/presets\")\n assert presets.status_code == 200\n provider_ids = {item[\"id\"] for item in presets.json()[\"providers\"]}\n expected = {\"openai\", \"qwen\", \"zhipu\", \"deepseek\", \"kimi\", \"minimax\", \"anthropic\", \"techmatch_local_agent\"}\n assert expected.issubset(provider_ids)\n assert \"local_agent\" in presets.json()\n deepseek = next(item for item in presets.json()[\"providers\"] if item[\"id\"] == \"deepseek\")\n deepseek_model_ids = {item[\"id\"] for item in deepseek[\"models\"]}\n assert {\"deepseek-v4-flash\", \"deepseek-v4-pro\"}.issubset(deepseek_model_ids)\n\n invalid_ocr = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"vision_provider_id\": \"deepseek\",\n \"vision_api_base\": \"https://api.deepseek.com\",\n \"vision_model\": \"deepseek-chat\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n bad = await client.put(\"/api/v1/ai-settings\", json=invalid_ocr, headers=platform_headers)\n assert bad.status_code == 422\n\n valid = {\n **invalid_ocr,\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n }\n saved = await client.put(\"/api/v1/ai-settings\", json=valid, headers=platform_headers)\n assert saved.status_code == 200\n body = saved.json()\n assert body[\"provider_id\"] == \"deepseek\"\n assert body[\"vision_model\"] == \"qwen3-vl-flash\"\n assert \"api_key\" not in body\n\n\n@pytest.mark.asyncio\nasync def test_local_agent_status_defaults_without_agent(client: AsyncClient):\n platform_headers = await create_platform_headers()\n response = await client.get(\"/api/v1/ai-settings/local-agent/status\", headers=platform_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"configured\"] is False\n assert body[\"online\"] is False\n assert body[\"service_url\"] == \"http://127.0.0.1:8765/v1\"\n assert body[\"data_boundary\"][\"raw_resumes\"] == \"local_agent\"\n\n\n@pytest.mark.asyncio\nasync def test_local_mode_accepts_local_agent_provider(client: AsyncClient):\n platform_headers = await create_platform_headers()\n payload = {\n \"provider_id\": \"techmatch_local_agent\",\n \"api_base\": \"https://api.deepseek.com\",\n \"parse_model\": \"qwen2.5:7b-instruct\",\n \"analyze_model\": \"qwen2.5:7b-instruct\",\n \"evaluation_model\": \"qwen2.5:7b-instruct\",\n \"vision_provider_id\": \"techmatch_local_agent\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5vl:7b\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"embedding_provider_id\": \"local_sentence_transformers\",\n \"embedding_model\": \"BAAI/bge-small-zh-v1.5\",\n \"local_mode_enabled\": True,\n \"local_service_url\": \"http://127.0.0.1:8765/v1\",\n \"allow_cloud_fallback\": False,\n \"extra_headers\": {\"X-TechMatch-Local-Token\": \"change-me\"},\n }\n saved = await client.put(\"/api/v1/ai-settings\", json=payload, headers=platform_headers)\n assert saved.status_code == 200\n body = saved.json()\n assert body[\"provider_id\"] == \"techmatch_local_agent\"\n assert body[\"local_mode_enabled\"] is True\n assert body[\"local_service_url\"] == \"http://127.0.0.1:8765/v1\"\n assert body[\"allow_cloud_fallback\"] is False\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_rejects_insecure_cloud_url_and_forbidden_headers(client: AsyncClient):\n platform_headers = await create_platform_headers()\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"http://api.deepseek.com\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n insecure = await client.put(\"/api/v1/ai-settings\", json=payload, headers=platform_headers)\n assert insecure.status_code == 422\n\n forbidden_header = await client.put(\n \"/api/v1/ai-settings\",\n json={\n **payload,\n \"api_base\": \"https://api.deepseek.com\",\n \"extra_headers\": {\"Authorization\": \"Bearer leaked\"},\n },\n headers=platform_headers,\n )\n assert forbidden_header.status_code == 422\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_accepts_unlisted_text_model_ids(client: AsyncClient):\n platform_headers = await create_platform_headers()\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com\",\n \"parse_model\": \"deepseek-v4-flash\",\n \"analyze_model\": \"future-deepseek-model\",\n \"evaluation_model\": \"future-deepseek-evaluator\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n response = await client.put(\"/api/v1/ai-settings\", json=payload, headers=platform_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"parse_model\"] == \"deepseek-v4-flash\"\n assert body[\"analyze_model\"] == \"future-deepseek-model\"\n assert body[\"evaluation_model\"] == \"future-deepseek-evaluator\"\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_accepts_unlisted_text_models_for_other_providers(client: AsyncClient):\n platform_headers = await create_platform_headers()\n payload = {\n \"provider_id\": \"qwen\",\n \"api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"parse_model\": \"qwen-future-release\",\n \"analyze_model\": \"qwen-future-pro\",\n \"evaluation_model\": \"qwen-future-evaluator\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n response = await client.put(\"/api/v1/ai-settings\", json=payload, headers=platform_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"provider_id\"] == \"qwen\"\n assert body[\"parse_model\"] == \"qwen-future-release\"\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_update_requires_admin_role(client: AsyncClient):\n platform_member_headers = await create_platform_headers(\"ops-member@example.com\", role=\"member\")\n payload = {\n \"provider_id\": \"qwen\",\n \"api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"parse_model\": \"qwen-plus\",\n \"analyze_model\": \"qwen-plus\",\n \"evaluation_model\": \"qwen-plus\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n\n response = await client.put(\"/api/v1/ai-settings\", json=payload, headers=platform_member_headers)\n\n assert response.status_code == 403\n assert \"需要 admin\" in response.json()[\"detail\"]\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_update_requires_platform_admin(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"qwen\",\n \"api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"parse_model\": \"qwen-plus\",\n \"analyze_model\": \"qwen-plus\",\n \"evaluation_model\": \"qwen-plus\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n\n response = await client.put(\"/api/v1/ai-settings\", json=payload, headers=auth_headers)\n\n assert response.status_code == 403\n assert \"平台运营管理员\" in response.json()[\"detail\"]\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_masks_extra_headers_after_save(client: AsyncClient):\n platform_headers = await create_platform_headers()\n payload = {\n \"provider_id\": \"techmatch_local_agent\",\n \"api_base\": \"https://api.deepseek.com\",\n \"parse_model\": \"qwen2.5:7b-instruct\",\n \"analyze_model\": \"qwen2.5:7b-instruct\",\n \"evaluation_model\": \"qwen2.5:7b-instruct\",\n \"vision_provider_id\": \"techmatch_local_agent\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5vl:7b\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"local_mode_enabled\": True,\n \"local_service_url\": \"http://127.0.0.1:8765/v1\",\n \"allow_cloud_fallback\": False,\n \"extra_headers\": {\"X-TechMatch-Local-Token\": \"secret-local-token\"},\n }\n\n saved = await client.put(\"/api/v1/ai-settings\", json=payload, headers=platform_headers)\n assert saved.status_code == 200\n assert saved.json()[\"extra_headers\"] == {\"X-TechMatch-Local-Token\": \"********\"}\n\n loaded = await client.get(\"/api/v1/ai-settings\", headers=platform_headers)\n assert loaded.status_code == 200\n assert loaded.json()[\"extra_headers\"] == {\"X-TechMatch-Local-Token\": \"********\"}\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_serializes_legacy_null_text_as_defaults(client: AsyncClient):\n platform_headers = await create_platform_headers()\n initial = await client.get(\"/api/v1/ai-settings\", headers=platform_headers)\n assert initial.status_code == 200\n\n async with TestSessionLocal() as db:\n row = (await db.execute(select(AISettings))).scalar_one()\n row.api_base = \"null\"\n row.vision_api_base = \"null\"\n row.local_service_url = \"null\"\n row.parse_model = \"null\"\n row.analyze_model = \"undefined\"\n row.vision_model = \"none\"\n await db.commit()\n\n response = await client.get(\"/api/v1/ai-settings\", headers=platform_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"api_base\"] == \"https://api.deepseek.com\"\n assert body[\"vision_api_base\"] == \"https://dashscope.aliyuncs.com/compatible-mode/v1\"\n assert body[\"local_service_url\"] is None\n assert body[\"parse_model\"] == \"deepseek-v4-flash\"\n assert body[\"analyze_model\"] == \"deepseek-v4-flash\"\n assert body[\"vision_model\"] == \"qwen3-vl-flash\"\n\n\n@pytest.mark.asyncio\nasync def test_text_model_test_ignores_local_agent_routing(\n client: AsyncClient,\n monkeypatch,\n):\n platform_headers = await create_platform_headers()\n captured = {}\n\n async def fake_run(runtime, _client, **kwargs):\n captured[\"runtime\"] = runtime\n captured[\"kwargs\"] = kwargs\n message = SimpleNamespace(content=\"ok\")\n return SimpleNamespace(choices=[SimpleNamespace(message=message)]), runtime\n\n monkeypatch.setattr(\"app.services.ai_settings_service.create_llm_client\", lambda runtime: object())\n monkeypatch.setattr(\"app.services.ai_settings_service.run_chat_completion_with_fallback\", fake_run)\n\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"evaluation_model\": \"deepseek-reasoner\",\n \"api_key\": \"sk-user-text\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"vision_api_key\": \"sk-user-vision\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"local_mode_enabled\": True,\n \"local_service_url\": \"http://127.0.0.1:8765/v1\",\n \"allow_cloud_fallback\": False,\n \"extra_headers\": {},\n }\n response = await client.post(\"/api/v1/ai-settings/test/text\", json=payload, headers=platform_headers)\n assert response.status_code == 200\n\n runtime = captured[\"runtime\"]\n assert runtime.local_mode_enabled is False\n assert runtime.request_origin == \"cloud\"\n assert runtime.api_base == \"https://api.deepseek.com\"\n assert captured[\"kwargs\"][\"model\"] == \"deepseek-chat\"\n assert response.json()[\"metadata\"][\"request_origin\"] == \"cloud\"\n"}, "020d4f8dc3e8a3a7f2457fca7730e9ee3632f6af": {"t": 1785769094.34593, "n": 12183, "h": "f152f52b1b442f18", "c": "\"\"\"AI settings API tests.\"\"\"\n\nfrom types import SimpleNamespace\n\nimport pytest\nfrom httpx import AsyncClient\nfrom sqlalchemy import select\n\nfrom app.models.ai_settings import AISettings\nfrom app.models.user import User\nfrom tests.conftest import TestSessionLocal\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_presets_and_update(client: AsyncClient, auth_headers: dict):\n presets = await client.get(\"/api/v1/ai-settings/presets\", headers=auth_headers)\n assert presets.status_code == 200\n provider_ids = {item[\"id\"] for item in presets.json()[\"providers\"]}\n expected = {\"openai\", \"qwen\", \"zhipu\", \"deepseek\", \"kimi\", \"minimax\", \"anthropic\", \"techmatch_local_agent\"}\n assert expected.issubset(provider_ids)\n assert \"local_agent\" in presets.json()\n deepseek = next(item for item in presets.json()[\"providers\"] if item[\"id\"] == \"deepseek\")\n deepseek_model_ids = {item[\"id\"] for item in deepseek[\"models\"]}\n assert {\"deepseek-v4-flash\", \"deepseek-v4-pro\"}.issubset(deepseek_model_ids)\n\n invalid_ocr = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"vision_provider_id\": \"deepseek\",\n \"vision_api_base\": \"https://api.deepseek.com/v1\",\n \"vision_model\": \"deepseek-chat\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n bad = await client.put(\"/api/v1/ai-settings\", json=invalid_ocr, headers=auth_headers)\n assert bad.status_code == 422\n\n valid = {\n **invalid_ocr,\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n }\n saved = await client.put(\"/api/v1/ai-settings\", json=valid, headers=auth_headers)\n assert saved.status_code == 200\n body = saved.json()\n assert body[\"provider_id\"] == \"deepseek\"\n assert body[\"vision_model\"] == \"qwen3-vl-flash\"\n assert \"api_key\" not in body\n\n\n@pytest.mark.asyncio\nasync def test_local_agent_status_defaults_without_agent(client: AsyncClient, auth_headers: dict):\n response = await client.get(\"/api/v1/ai-settings/local-agent/status\", headers=auth_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"configured\"] is False\n assert body[\"online\"] is False\n assert body[\"service_url\"] == \"http://127.0.0.1:8765/v1\"\n assert body[\"data_boundary\"][\"raw_resumes\"] == \"local_agent\"\n\n\n@pytest.mark.asyncio\nasync def test_local_mode_accepts_local_agent_provider(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"techmatch_local_agent\",\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"parse_model\": \"qwen2.5:7b-instruct\",\n \"analyze_model\": \"qwen2.5:7b-instruct\",\n \"evaluation_model\": \"qwen2.5:7b-instruct\",\n \"vision_provider_id\": \"techmatch_local_agent\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5vl:7b\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"embedding_provider_id\": \"local_sentence_transformers\",\n \"embedding_model\": \"BAAI/bge-small-zh-v1.5\",\n \"local_mode_enabled\": True,\n \"local_service_url\": \"http://127.0.0.1:8765/v1\",\n \"allow_cloud_fallback\": False,\n \"extra_headers\": {\"X-TechMatch-Local-Token\": \"change-me\"},\n }\n saved = await client.put(\"/api/v1/ai-settings\", json=payload, headers=auth_headers)\n assert saved.status_code == 200\n body = saved.json()\n assert body[\"provider_id\"] == \"techmatch_local_agent\"\n assert body[\"local_mode_enabled\"] is True\n assert body[\"local_service_url\"] == \"http://127.0.0.1:8765/v1\"\n assert body[\"allow_cloud_fallback\"] is False\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_rejects_insecure_cloud_url_and_forbidden_headers(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"http://api.deepseek.com/v1\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n insecure = await client.put(\"/api/v1/ai-settings\", json=payload, headers=auth_headers)\n assert insecure.status_code == 422\n\n forbidden_header = await client.put(\n \"/api/v1/ai-settings\",\n json={\n **payload,\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"extra_headers\": {\"Authorization\": \"Bearer leaked\"},\n },\n headers=auth_headers,\n )\n assert forbidden_header.status_code == 422\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_accepts_unlisted_text_model_ids(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"parse_model\": \"deepseek-v4-flash\",\n \"analyze_model\": \"future-deepseek-model\",\n \"evaluation_model\": \"future-deepseek-evaluator\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n response = await client.put(\"/api/v1/ai-settings\", json=payload, headers=auth_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"parse_model\"] == \"deepseek-v4-flash\"\n assert body[\"analyze_model\"] == \"future-deepseek-model\"\n assert body[\"evaluation_model\"] == \"future-deepseek-evaluator\"\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_accepts_unlisted_text_models_for_other_providers(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"qwen\",\n \"api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"parse_model\": \"qwen-future-release\",\n \"analyze_model\": \"qwen-future-pro\",\n \"evaluation_model\": \"qwen-future-evaluator\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n response = await client.put(\"/api/v1/ai-settings\", json=payload, headers=auth_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"provider_id\"] == \"qwen\"\n assert body[\"parse_model\"] == \"qwen-future-release\"\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_update_requires_admin_role(client: AsyncClient, auth_headers: dict):\n async with TestSessionLocal() as db:\n user = (await db.execute(select(User).where(User.email == \"test@example.com\"))).scalar_one()\n user.role = \"member\"\n await db.commit()\n\n payload = {\n \"provider_id\": \"qwen\",\n \"api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"parse_model\": \"qwen-plus\",\n \"analyze_model\": \"qwen-plus\",\n \"evaluation_model\": \"qwen-plus\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n\n response = await client.put(\"/api/v1/ai-settings\", json=payload, headers=auth_headers)\n\n assert response.status_code == 403\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_masks_extra_headers_after_save(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"techmatch_local_agent\",\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"parse_model\": \"qwen2.5:7b-instruct\",\n \"analyze_model\": \"qwen2.5:7b-instruct\",\n \"evaluation_model\": \"qwen2.5:7b-instruct\",\n \"vision_provider_id\": \"techmatch_local_agent\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5vl:7b\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"local_mode_enabled\": True,\n \"local_service_url\": \"http://127.0.0.1:8765/v1\",\n \"allow_cloud_fallback\": False,\n \"extra_headers\": {\"X-TechMatch-Local-Token\": \"secret-local-token\"},\n }\n\n saved = await client.put(\"/api/v1/ai-settings\", json=payload, headers=auth_headers)\n assert saved.status_code == 200\n assert saved.json()[\"extra_headers\"] == {\"X-TechMatch-Local-Token\": \"********\"}\n\n loaded = await client.get(\"/api/v1/ai-settings\", headers=auth_headers)\n assert loaded.status_code == 200\n assert loaded.json()[\"extra_headers\"] == {\"X-TechMatch-Local-Token\": \"********\"}\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_serializes_legacy_null_text_as_defaults(client: AsyncClient, auth_headers: dict):\n initial = await client.get(\"/api/v1/ai-settings\", headers=auth_headers)\n assert initial.status_code == 200\n\n async with TestSessionLocal() as db:\n row = (await db.execute(select(AISettings))).scalar_one()\n row.api_base = \"null\"\n row.vision_api_base = \"null\"\n row.local_service_url = \"null\"\n row.parse_model = \"null\"\n row.analyze_model = \"undefined\"\n row.vision_model = \"none\"\n await db.commit()\n\n response = await client.get(\"/api/v1/ai-settings\", headers=auth_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"api_base\"] == \"https://token-plan-cn.xiaomimimo.com/v1\"\n assert body[\"vision_api_base\"] == \"https://dashscope.aliyuncs.com/compatible-mode/v1\"\n assert body[\"local_service_url\"] is None\n assert body[\"parse_model\"] == \"mimo-v2-pro\"\n assert body[\"analyze_model\"] == \"mimo-v2-pro\"\n assert body[\"vision_model\"] == \"qwen3-vl-flash\"\n\n\n@pytest.mark.asyncio\nasync def test_text_model_test_ignores_local_agent_routing(\n client: AsyncClient,\n auth_headers: dict,\n monkeypatch,\n):\n captured = {}\n\n async def fake_run(runtime, _client, **kwargs):\n captured[\"runtime\"] = runtime\n captured[\"kwargs\"] = kwargs\n message = SimpleNamespace(content=\"ok\")\n return SimpleNamespace(choices=[SimpleNamespace(message=message)]), runtime\n\n monkeypatch.setattr(\"app.services.ai_settings_service.create_llm_client\", lambda runtime: object())\n monkeypatch.setattr(\"app.services.ai_settings_service.run_chat_completion_with_fallback\", fake_run)\n\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"evaluation_model\": \"deepseek-reasoner\",\n \"api_key\": \"sk-user-text\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen3-vl-flash\",\n \"vision_api_key\": \"sk-user-vision\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"local_mode_enabled\": True,\n \"local_service_url\": \"http://127.0.0.1:8765/v1\",\n \"allow_cloud_fallback\": False,\n \"extra_headers\": {},\n }\n response = await client.post(\"/api/v1/ai-settings/test/text\", json=payload, headers=auth_headers)\n assert response.status_code == 200\n\n runtime = captured[\"runtime\"]\n assert runtime.local_mode_enabled is False\n assert runtime.request_origin == \"cloud\"\n assert runtime.api_base == \"https://api.deepseek.com/v1\"\n assert captured[\"kwargs\"][\"model\"] == \"deepseek-chat\"\n assert response.json()[\"metadata\"][\"request_origin\"] == \"cloud\"\n"}, "042bf0b3abbf497e020c730ffa94ff1c33fc3b67": {"t": 1785769095.5166717, "n": 7256, "h": "94df2062939bfc9d", "c": "\"\"\"AI settings API tests.\"\"\"\n\nfrom types import SimpleNamespace\n\nimport pytest\nfrom httpx import AsyncClient\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_presets_and_update(client: AsyncClient, auth_headers: dict):\n presets = await client.get(\"/api/v1/ai-settings/presets\", headers=auth_headers)\n assert presets.status_code == 200\n provider_ids = {item[\"id\"] for item in presets.json()[\"providers\"]}\n expected = {\"openai\", \"qwen\", \"zhipu\", \"deepseek\", \"kimi\", \"minimax\", \"anthropic\", \"techmatch_local_agent\"}\n assert expected.issubset(provider_ids)\n assert \"local_agent\" in presets.json()\n\n invalid_ocr = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"vision_provider_id\": \"deepseek\",\n \"vision_api_base\": \"https://api.deepseek.com/v1\",\n \"vision_model\": \"deepseek-chat\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n bad = await client.put(\"/api/v1/ai-settings\", json=invalid_ocr, headers=auth_headers)\n assert bad.status_code == 422\n\n valid = {\n **invalid_ocr,\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5-vl-7b-instruct\",\n }\n saved = await client.put(\"/api/v1/ai-settings\", json=valid, headers=auth_headers)\n assert saved.status_code == 200\n body = saved.json()\n assert body[\"provider_id\"] == \"deepseek\"\n assert body[\"vision_model\"] == \"qwen2.5-vl-7b-instruct\"\n assert \"api_key\" not in body\n\n\n@pytest.mark.asyncio\nasync def test_local_agent_status_defaults_without_agent(client: AsyncClient, auth_headers: dict):\n response = await client.get(\"/api/v1/ai-settings/local-agent/status\", headers=auth_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"configured\"] is False\n assert body[\"online\"] is False\n assert body[\"service_url\"] == \"http://127.0.0.1:8765/v1\"\n assert body[\"data_boundary\"][\"raw_resumes\"] == \"local_agent\"\n\n\n@pytest.mark.asyncio\nasync def test_local_mode_accepts_local_agent_provider(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"techmatch_local_agent\",\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"parse_model\": \"qwen2.5:7b-instruct\",\n \"analyze_model\": \"qwen2.5:7b-instruct\",\n \"evaluation_model\": \"qwen2.5:7b-instruct\",\n \"vision_provider_id\": \"techmatch_local_agent\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5vl:7b\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"embedding_provider_id\": \"local_sentence_transformers\",\n \"embedding_model\": \"BAAI/bge-small-zh-v1.5\",\n \"local_mode_enabled\": True,\n \"local_service_url\": \"http://127.0.0.1:8765/v1\",\n \"allow_cloud_fallback\": False,\n \"extra_headers\": {\"X-TechMatch-Local-Token\": \"change-me\"},\n }\n saved = await client.put(\"/api/v1/ai-settings\", json=payload, headers=auth_headers)\n assert saved.status_code == 200\n body = saved.json()\n assert body[\"provider_id\"] == \"techmatch_local_agent\"\n assert body[\"local_mode_enabled\"] is True\n assert body[\"local_service_url\"] == \"http://127.0.0.1:8765/v1\"\n assert body[\"allow_cloud_fallback\"] is False\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_rejects_insecure_cloud_url_and_forbidden_headers(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"http://api.deepseek.com/v1\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5-vl-7b-instruct\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n insecure = await client.put(\"/api/v1/ai-settings\", json=payload, headers=auth_headers)\n assert insecure.status_code == 422\n\n forbidden_header = await client.put(\n \"/api/v1/ai-settings\",\n json={\n **payload,\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"extra_headers\": {\"Authorization\": \"Bearer leaked\"},\n },\n headers=auth_headers,\n )\n assert forbidden_header.status_code == 422\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_test_endpoint_uses_unsaved_payload_validation(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"parse_model\": \"unknown-model\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5-vl-7b-instruct\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n response = await client.post(\"/api/v1/ai-settings/test/text\", json=payload, headers=auth_headers)\n assert response.status_code == 422\n\n\n@pytest.mark.asyncio\nasync def test_text_model_test_ignores_local_agent_routing(\n client: AsyncClient,\n auth_headers: dict,\n monkeypatch,\n):\n captured = {}\n\n async def fake_run(runtime, _client, **kwargs):\n captured[\"runtime\"] = runtime\n captured[\"kwargs\"] = kwargs\n message = SimpleNamespace(content=\"ok\")\n return SimpleNamespace(choices=[SimpleNamespace(message=message)]), runtime\n\n monkeypatch.setattr(\"app.services.ai_settings_service.create_llm_client\", lambda runtime: object())\n monkeypatch.setattr(\"app.services.ai_settings_service.run_chat_completion_with_fallback\", fake_run)\n\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"evaluation_model\": \"deepseek-reasoner\",\n \"api_key\": \"sk-user-text\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5-vl-7b-instruct\",\n \"vision_api_key\": \"sk-user-vision\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"local_mode_enabled\": True,\n \"local_service_url\": \"http://127.0.0.1:8765/v1\",\n \"allow_cloud_fallback\": False,\n \"extra_headers\": {},\n }\n response = await client.post(\"/api/v1/ai-settings/test/text\", json=payload, headers=auth_headers)\n assert response.status_code == 200\n\n runtime = captured[\"runtime\"]\n assert runtime.local_mode_enabled is False\n assert runtime.request_origin == \"cloud\"\n assert runtime.api_base == \"https://api.deepseek.com/v1\"\n assert captured[\"kwargs\"][\"model\"] == \"deepseek-chat\"\n assert response.json()[\"metadata\"][\"request_origin\"] == \"cloud\"\n"}, "db29b394ac2312b08cce322ea6863e9f322c0c38": {"t": 1785769096.7363272, "n": 5371, "h": "a37cbde3b3cd92d4", "c": "\"\"\"AI settings API tests.\"\"\"\n\nimport pytest\nfrom httpx import AsyncClient\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_presets_and_update(client: AsyncClient, auth_headers: dict):\n presets = await client.get(\"/api/v1/ai-settings/presets\", headers=auth_headers)\n assert presets.status_code == 200\n provider_ids = {item[\"id\"] for item in presets.json()[\"providers\"]}\n expected = {\"openai\", \"qwen\", \"zhipu\", \"deepseek\", \"kimi\", \"minimax\", \"anthropic\", \"techmatch_local_agent\"}\n assert expected.issubset(provider_ids)\n assert \"local_agent\" in presets.json()\n\n invalid_ocr = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"vision_provider_id\": \"deepseek\",\n \"vision_api_base\": \"https://api.deepseek.com/v1\",\n \"vision_model\": \"deepseek-chat\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n bad = await client.put(\"/api/v1/ai-settings\", json=invalid_ocr, headers=auth_headers)\n assert bad.status_code == 422\n\n valid = {\n **invalid_ocr,\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5-vl-7b-instruct\",\n }\n saved = await client.put(\"/api/v1/ai-settings\", json=valid, headers=auth_headers)\n assert saved.status_code == 200\n body = saved.json()\n assert body[\"provider_id\"] == \"deepseek\"\n assert body[\"vision_model\"] == \"qwen2.5-vl-7b-instruct\"\n assert \"api_key\" not in body\n\n\n@pytest.mark.asyncio\nasync def test_local_agent_status_defaults_without_agent(client: AsyncClient, auth_headers: dict):\n response = await client.get(\"/api/v1/ai-settings/local-agent/status\", headers=auth_headers)\n assert response.status_code == 200\n body = response.json()\n assert body[\"configured\"] is False\n assert body[\"online\"] is False\n assert body[\"service_url\"] == \"http://127.0.0.1:8765/v1\"\n assert body[\"data_boundary\"][\"raw_resumes\"] == \"local_agent\"\n\n\n@pytest.mark.asyncio\nasync def test_local_mode_accepts_local_agent_provider(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"techmatch_local_agent\",\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"parse_model\": \"qwen2.5:7b-instruct\",\n \"analyze_model\": \"qwen2.5:7b-instruct\",\n \"evaluation_model\": \"qwen2.5:7b-instruct\",\n \"vision_provider_id\": \"techmatch_local_agent\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5vl:7b\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"embedding_provider_id\": \"local_sentence_transformers\",\n \"embedding_model\": \"BAAI/bge-small-zh-v1.5\",\n \"local_mode_enabled\": True,\n \"local_service_url\": \"http://127.0.0.1:8765/v1\",\n \"allow_cloud_fallback\": False,\n \"extra_headers\": {\"X-TechMatch-Local-Token\": \"change-me\"},\n }\n saved = await client.put(\"/api/v1/ai-settings\", json=payload, headers=auth_headers)\n assert saved.status_code == 200\n body = saved.json()\n assert body[\"provider_id\"] == \"techmatch_local_agent\"\n assert body[\"local_mode_enabled\"] is True\n assert body[\"local_service_url\"] == \"http://127.0.0.1:8765/v1\"\n assert body[\"allow_cloud_fallback\"] is False\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_rejects_insecure_cloud_url_and_forbidden_headers(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"http://api.deepseek.com/v1\",\n \"parse_model\": \"deepseek-chat\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5-vl-7b-instruct\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n insecure = await client.put(\"/api/v1/ai-settings\", json=payload, headers=auth_headers)\n assert insecure.status_code == 422\n\n forbidden_header = await client.put(\n \"/api/v1/ai-settings\",\n json={\n **payload,\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"extra_headers\": {\"Authorization\": \"Bearer leaked\"},\n },\n headers=auth_headers,\n )\n assert forbidden_header.status_code == 422\n\n\n@pytest.mark.asyncio\nasync def test_ai_settings_test_endpoint_uses_unsaved_payload_validation(client: AsyncClient, auth_headers: dict):\n payload = {\n \"provider_id\": \"deepseek\",\n \"api_base\": \"https://api.deepseek.com/v1\",\n \"parse_model\": \"unknown-model\",\n \"analyze_model\": \"deepseek-reasoner\",\n \"vision_provider_id\": \"qwen\",\n \"vision_api_base\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"vision_model\": \"qwen2.5-vl-7b-instruct\",\n \"max_tokens_parse\": 4096,\n \"max_tokens_analyze\": 8192,\n \"max_tokens_vision\": 4096,\n \"extra_headers\": {},\n }\n response = await client.post(\"/api/v1/ai-settings/test/text\", json=payload, headers=auth_headers)\n assert response.status_code == 422\n"}}}}