"""Server E2E 集成测试 - 完整流程""" import pytest from unittest.mock import AsyncMock from fastapi.testclient import TestClient from agentkit.core.protocol import AgentStatus from agentkit.llm.gateway import LLMGateway from agentkit.llm.protocol import LLMProvider, LLMRequest, LLMResponse, TokenUsage from agentkit.skills.base import Skill, SkillConfig from agentkit.skills.registry import SkillRegistry from agentkit.tools.registry import ToolRegistry from agentkit.server.app import create_app class MockLLMProvider(LLMProvider): """Mock LLM Provider for integration tests""" def __init__(self): self.call_count = 0 async def chat(self, request: LLMRequest) -> LLMResponse: self.call_count += 1 return LLMResponse( content='{"result": "integration test output", "content": "This is the generated content from the skill"}', model="mock-model", usage=TokenUsage(prompt_tokens=50, completion_tokens=100), ) @pytest.fixture def llm_gateway(): gw = LLMGateway() gw.register_provider("mock", MockLLMProvider()) return gw @pytest.fixture def skill_registry(): return SkillRegistry() @pytest.fixture def tool_registry(): return ToolRegistry() @pytest.fixture def app(llm_gateway, skill_registry, tool_registry): return create_app( llm_gateway=llm_gateway, skill_registry=skill_registry, tool_registry=tool_registry, ) @pytest.fixture def client(app): return TestClient(app) class TestFullFlow: """完整流程:register skill → create agent → submit task → get result""" def test_register_skill_create_agent_submit_task(self, client): # Step 1: Register a skill skill_response = client.post( "/api/v1/skills", json={ "config": { "name": "content_writer", "agent_type": "content_generation", "task_mode": "llm_generate", "description": "Content writing skill", "prompt": { "identity": "You are a content writer", "instructions": "Write high-quality content", "output_format": "JSON", }, "intent": { "keywords": ["write", "content", "article"], "description": "Content writing and generation", }, "quality_gate": { "required_fields": ["content"], "min_word_count": 5, }, } }, ) assert skill_response.status_code == 201 # Step 2: Create agent from skill agent_response = client.post( "/api/v1/agents", json={"skill_name": "content_writer"}, ) assert agent_response.status_code == 201 agent_data = agent_response.json() assert agent_data["name"] == "content_writer" # Step 3: Verify agent is listed list_response = client.get("/api/v1/agents") assert list_response.status_code == 200 agents = list_response.json() assert len(agents) == 1 assert agents[0]["name"] == "content_writer" # Step 4: Submit task using skill_name task_response = client.post( "/api/v1/tasks", json={ "input_data": {"query": "Write an article about AI"}, "skill_name": "content_writer", }, ) assert task_response.status_code == 200 task_data = task_response.json() # Result should contain standardized output assert "skill_name" in task_data or "data" in task_data or "output" in task_data # Step 5: Verify skill is listed skills_response = client.get("/api/v1/skills") assert skills_response.status_code == 200 skills = skills_response.json() assert len(skills) >= 1 def test_submit_task_auto_routes_to_skill(self, client): """Intent Router 自动路由到正确的 skill""" # Register two skills with different keywords client.post( "/api/v1/skills", json={ "config": { "name": "translator", "agent_type": "translation", "task_mode": "llm_generate", "prompt": {"identity": "Translator", "instructions": "Translate text"}, "intent": { "keywords": ["translate", "翻译"], "description": "Translation skill", }, } }, ) client.post( "/api/v1/skills", json={ "config": { "name": "summarizer", "agent_type": "summarization", "task_mode": "llm_generate", "prompt": {"identity": "Summarizer", "instructions": "Summarize text"}, "intent": { "keywords": ["summarize", "摘要"], "description": "Summarization skill", }, } }, ) # Submit task with keyword matching "translate" response = client.post( "/api/v1/tasks", json={ "input_data": {"query": "Please translate this text to English"}, }, ) # Should route to translator skill via keyword matching assert response.status_code == 200 def test_delete_agent_then_submit_task_error(self, client): """Delete agent → submit task → appropriate error""" # Register skill and create agent client.post( "/api/v1/skills", json={ "config": { "name": "deletable_skill", "agent_type": "deletable_type", "task_mode": "llm_generate", "prompt": {"identity": "Deletable"}, "intent": {"keywords": ["delete"], "description": "Deletable skill"}, } }, ) client.post( "/api/v1/agents", json={"skill_name": "deletable_skill"}, ) # Delete the agent delete_response = client.delete("/api/v1/agents/deletable_skill") assert delete_response.status_code == 204 # Submit task referencing deleted agent task_response = client.post( "/api/v1/tasks", json={ "input_data": {"query": "test"}, "agent_name": "deletable_skill", }, ) # Should return 404 since agent was deleted assert task_response.status_code == 404 def test_health_check_in_flow(self, client): """Health check works during full flow""" response = client.get("/api/v1/health") assert response.status_code == 200 data = response.json() assert data["status"] in ("ok", "healthy") def test_llm_usage_after_tasks(self, client): """LLM usage stats available after task execution""" # Register skill and submit a task client.post( "/api/v1/skills", json={ "config": { "name": "usage_skill", "agent_type": "usage_type", "task_mode": "llm_generate", "prompt": {"identity": "Usage Skill"}, "intent": {"keywords": ["usage"], "description": "Usage skill"}, } }, ) client.post( "/api/v1/tasks", json={ "input_data": {"query": "test usage"}, "skill_name": "usage_skill", }, ) # Check usage response = client.get("/api/v1/llm/usage") assert response.status_code == 200