Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
14924a8
feat: initial clean scaffold for Pet Care Assistant
megz2020 Feb 19, 2026
ee9cce9
refactor: extract service architecture with comprehensive testing
megz2020 Feb 20, 2026
a5e9beb
Revise README.md for Pet Care Assistant
Rizwan-095 Feb 19, 2026
6cf95a8
Delete community/pet-care-assistant/config.json
Rizwan-095 Feb 19, 2026
6afe40e
fix: remove os.getenv() for OpenHome live editor compatibility
megz2020 Feb 20, 2026
b6bb44a
fix: add type annotations to service fields for Pydantic compatibility
megz2020 Feb 20, 2026
852af88
refactor: clean comments, rewrite README with architecture diagram
megz2020 Feb 20, 2026
02296f5
fix: correct reset_all classification and add pet inventory lookup
megz2020 Feb 20, 2026
0a97661
feat: add day-of-week reminders, friendly onboarding, LLM vet matchin…
megz2020 Feb 21, 2026
d55c00a
style: auto-format Python files with autoflake + autopep8
github-actions[bot] Feb 21, 2026
6133433
fix: empty tests/__init__.py to satisfy linter requirement
megz2020 Feb 21, 2026
a98a74e
fix: inline config values and add register capability tag
megz2020 Feb 21, 2026
28ee2c4
style: auto-format Python files with autoflake + autopep8
github-actions[bot] Feb 21, 2026
f2d3e7f
fix: register_capability
megz2020 Feb 21, 2026
2688ae2
refactor: revert to inline classes — live editor errors on external f…
megz2020 Feb 22, 2026
f54997f
style: auto-format Python files with autoflake + autopep8
github-actions[bot] Feb 22, 2026
3392b15
fix: remove duplicate user_response() calls causing repeated command …
megz2020 Feb 22, 2026
8bbed2f
style: apply isort and black formatting
megz2020 Feb 22, 2026
8fbfe84
style: auto-format Python files with autoflake + autopep8
github-actions[bot] Feb 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
571 changes: 213 additions & 358 deletions community/pet-care-assistant/README.md

Large diffs are not rendered by default.

2,798 changes: 2,194 additions & 604 deletions community/pet-care-assistant/main.py

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions community/pet-care-assistant/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[pytest]
# Pytest configuration for Pet Care Assistant

testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*

# Show extra test summary info
addopts =
-v
--tb=short
--strict-markers
--cov=main
--cov-report=term-missing
--cov-report=html

# Markers for organizing tests
markers =
unit: Unit tests (fast, no external dependencies)
integration: Integration tests (may hit external APIs)
slow: Slow-running tests

# Asyncio configuration
asyncio_mode = auto
7 changes: 7 additions & 0 deletions community/pet-care-assistant/requirements-test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Test dependencies for Pet Care Assistant

pytest>=7.4.0
pytest-asyncio>=0.21.0
pytest-mock>=3.11.0
pytest-cov>=4.1.0
hypothesis>=6.82.0
Empty file.
100 changes: 100 additions & 0 deletions community/pet-care-assistant/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"""Shared test fixtures for Pet Care Assistant tests."""

import os
import sys
from unittest.mock import AsyncMock, MagicMock

import pytest


# Mock the OpenHome src modules before importing main
@pytest.fixture(scope="session", autouse=True)
def mock_src_modules():
"""Mock the src.agent modules that aren't available in test environment."""
# Create mock modules
mock_capability = MagicMock()
mock_capability.MatchingCapability = type(
"MatchingCapability",
(),
{"__init__": lambda self, unique_name="", matching_hotwords=None: None},
)

mock_capability_worker = MagicMock()
mock_capability_worker.CapabilityWorker = MagicMock

mock_main = MagicMock()
mock_main.AgentWorker = MagicMock

# Install mocks in sys.modules
sys.modules["src"] = MagicMock()
sys.modules["src.agent"] = MagicMock()
sys.modules["src.agent.capability"] = mock_capability
sys.modules["src.agent.capability_worker"] = mock_capability_worker
sys.modules["src.main"] = mock_main

# Add parent directory to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

yield

# Cleanup not strictly necessary for session-scope fixture


@pytest.fixture
def mock_worker():
"""Mock AgentWorker."""
worker = MagicMock()
worker.editor_logging_handler = MagicMock()
worker.editor_logging_handler.info = MagicMock()
worker.editor_logging_handler.error = MagicMock()
worker.editor_logging_handler.warning = MagicMock()
return worker


@pytest.fixture
def mock_capability_worker():
"""Mock CapabilityWorker."""
cw = MagicMock()
cw.speak = AsyncMock()
cw.user_response = AsyncMock()
cw.run_io_loop = AsyncMock()
cw.text_to_text_response = MagicMock()
cw.run_confirmation_loop = AsyncMock()
cw.check_if_file_exists = AsyncMock()
cw.read_file = AsyncMock()
cw.write_file = AsyncMock()
cw.delete_file = AsyncMock()
cw.resume_normal_flow = MagicMock()
return cw


@pytest.fixture
def capability(mock_worker, mock_capability_worker):
"""Create a PetCareAssistantCapability instance with mocked dependencies."""
from main import (
ActivityLogService,
ExternalAPIService,
LLMService,
PetCareAssistantCapability,
PetDataService,
)

cap = PetCareAssistantCapability(
unique_name="test_pet_care", matching_hotwords=["pet care", "my pets"]
)
cap.worker = mock_worker
cap.capability_worker = mock_capability_worker
cap.pet_data = {}
cap.activity_log = []
cap._geocode_cache = {}
cap._corrected_name = None

# Initialize all services
cap.pet_data_service = PetDataService(mock_capability_worker, mock_worker)
cap.activity_log_service = ActivityLogService(mock_worker, max_log_entries=500)
cap.external_api_service = ExternalAPIService(
mock_worker, serper_api_key="test_key"
)
cap.llm_service = LLMService(mock_capability_worker, mock_worker, cap.pet_data)

return cap
Loading