diff --git a/src/haiku/rag/a2a.py b/src/haiku/rag/a2a.py index bcd1692f..18322da1 100644 --- a/src/haiku/rag/a2a.py +++ b/src/haiku/rag/a2a.py @@ -23,6 +23,7 @@ try: Artifact, DataPart, Message, + Skill, TaskIdParams, TaskSendParams, TaskState, @@ -208,6 +209,29 @@ class LRUMemoryStorage(Storage[list["Message"]]): # type: ignore return await self.storage.submit_task(context_id, message) +def get_agent_skills() -> list[Skill]: + """Define the skills exposed by the haiku.rag A2A agent. + + Returns: + List of skills describing the agent's capabilities + """ + return [ + Skill( + id="document-qa", + name="Document Question Answering", + description="Answer questions based on a knowledge base of documents using semantic search and retrieval", + tags=["question-answering", "search", "knowledge-base", "rag"], + input_modes=["application/json"], + output_modes=["application/json"], + examples=[ + "What does the documentation say about authentication?", + "Find information about Python best practices", + "Show me the full API documentation", + ], + ) + ] + + def extract_question_from_task(task_history: list[Message]) -> str | None: """Extract the user's question from task history. @@ -412,5 +436,6 @@ def create_a2a_app(db_path: Path): broker=broker, name="haiku-rag", description="Conversational question answering agent powered by haiku.rag RAG system", + skills=get_agent_skills(), lifespan=lifespan, ) diff --git a/tests/test_a2a.py b/tests/test_a2a.py index 3ae9b404..9dc0cac8 100644 --- a/tests/test_a2a.py +++ b/tests/test_a2a.py @@ -227,3 +227,36 @@ async def test_a2a_app_creation(temp_db_path): assert app.name == "haiku-rag" assert app.description is not None assert "conversational" in app.description.lower() + + +@pytest.mark.asyncio +async def test_a2a_app_has_skills(temp_db_path): + """Test that A2A app exposes skills describing its capabilities.""" + from haiku.rag.a2a import create_a2a_app + + # Create a test database + async with HaikuRAG(temp_db_path) as client: + await client.create_document(content="Test document", uri="test_doc") + + # Create A2A app + app = create_a2a_app(temp_db_path) + + # Verify app has skills + assert app.skills is not None + assert len(app.skills) > 0 + + # Check that at least one skill exists + skill = app.skills[0] + assert "id" in skill + assert "name" in skill + assert "description" in skill + assert "tags" in skill + assert "input_modes" in skill + assert "output_modes" in skill + + # Verify the skill describes document search/QA capabilities + skill_text = f"{skill['name']} {skill['description']}".lower() + assert any( + keyword in skill_text + for keyword in ["search", "question", "answer", "document", "knowledge"] + )