From 0521c738ed164049d65619a80ec67b7f8efc48be Mon Sep 17 00:00:00 2001 From: Ovtcharov Date: Fri, 29 May 2026 10:09:08 -0700 Subject: [PATCH 1/8] fix(types): resolve remaining mypy errors missed by #1253 Suppresses no-any-return in providers and factory, fixes Optional defaults in database.py, adds type: ignore for file_watcher redefs, casts TransitionStatus in checkpoint_bridge. --- .../code/orchestration/factories/python_factory.py | 4 ++-- src/gaia/governance/checkpoint_bridge.py | 3 ++- src/gaia/llm/providers/claude.py | 2 +- src/gaia/llm/providers/openai_provider.py | 2 +- src/gaia/ui/database.py | 14 +++++++------- src/gaia/utils/file_watcher.py | 4 ++-- src/gaia/utils/parsing.py | 6 +++--- 7 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/gaia/agents/code/orchestration/factories/python_factory.py b/src/gaia/agents/code/orchestration/factories/python_factory.py index 308703ad0..c8ade3a01 100644 --- a/src/gaia/agents/code/orchestration/factories/python_factory.py +++ b/src/gaia/agents/code/orchestration/factories/python_factory.py @@ -7,7 +7,7 @@ """ from pathlib import Path -from typing import List +from typing import Any, Dict, List, cast from ..steps.base import UserContext from ..workflows.base import WorkflowPhase @@ -103,4 +103,4 @@ def get_validation_config(self, phase_name: str) -> dict: "test_command": "pytest", }, } - return configs.get(phase_name, {}) + return cast(Dict[str, Any], configs.get(phase_name, {})) diff --git a/src/gaia/governance/checkpoint_bridge.py b/src/gaia/governance/checkpoint_bridge.py index 9c7b5fd4b..a7c95245a 100644 --- a/src/gaia/governance/checkpoint_bridge.py +++ b/src/gaia/governance/checkpoint_bridge.py @@ -17,6 +17,7 @@ CheckpointResolution, GovernanceDecision, TransitionOutcome, + TransitionStatus, WorkflowTransition, new_id, utc_now_iso, @@ -100,7 +101,7 @@ def resolve_checkpoint( }, ) return TransitionOutcome( - status=outcome_status, + status=cast(TransitionStatus, outcome_status), reason=reason, checkpoint_id=checkpoint_id, metadata={"resolution": resolution.resolution}, diff --git a/src/gaia/llm/providers/claude.py b/src/gaia/llm/providers/claude.py index 789feff45..af29c82cd 100644 --- a/src/gaia/llm/providers/claude.py +++ b/src/gaia/llm/providers/claude.py @@ -74,7 +74,7 @@ def chat( response = self._client.messages.create(**params) if stream: return self._handle_stream(response) - return response.content[0].text + return response.content[0].text # type: ignore[no-any-return] # embed() inherited from ABC - raises NotSupportedError diff --git a/src/gaia/llm/providers/openai_provider.py b/src/gaia/llm/providers/openai_provider.py index ab204153a..0409a6c92 100644 --- a/src/gaia/llm/providers/openai_provider.py +++ b/src/gaia/llm/providers/openai_provider.py @@ -60,7 +60,7 @@ def chat( ) if stream: return self._handle_stream(response) - return response.choices[0].message.content + return response.choices[0].message.content # type: ignore[no-any-return] def embed( self, texts: list[str], model: str = "text-embedding-3-small", **kwargs diff --git a/src/gaia/ui/database.py b/src/gaia/ui/database.py index 918e88a0c..c998c0ad1 100644 --- a/src/gaia/ui/database.py +++ b/src/gaia/ui/database.py @@ -84,7 +84,7 @@ class ChatDatabase: """SQLite database for Agent UI sessions, messages, and documents.""" - def __init__(self, db_path: str = None): + def __init__(self, db_path: str | None = None): """Initialize database connection. Args: @@ -251,13 +251,13 @@ def _now(self) -> str: def create_session( self, - title: str = None, - model: str = None, - system_prompt: str = None, - document_ids: List[str] = None, + title: str | None = None, + model: str | None = None, + system_prompt: str | None = None, + document_ids: List[str] | None = None, private: bool = False, - agent_type: str = None, - device: str = None, + agent_type: str | None = None, + device: str | None = None, ) -> Dict[str, Any]: """Create a new chat session.""" session_id = str(uuid.uuid4()) diff --git a/src/gaia/utils/file_watcher.py b/src/gaia/utils/file_watcher.py index 2604d8108..fe8bbcde6 100644 --- a/src/gaia/utils/file_watcher.py +++ b/src/gaia/utils/file_watcher.py @@ -39,10 +39,10 @@ def on_new_file(path: str): WATCHDOG_AVAILABLE = True except ImportError: # Create dummy base class when watchdog is not available - class FileSystemEventHandler: + class FileSystemEventHandler: # type: ignore[no-redef] """Dummy base class when watchdog is not installed.""" - class FileSystemEvent: + class FileSystemEvent: # type: ignore[no-redef] """Dummy event class when watchdog is not installed.""" src_path: str = "" diff --git a/src/gaia/utils/parsing.py b/src/gaia/utils/parsing.py index 1151fc0f2..a0ebb9713 100644 --- a/src/gaia/utils/parsing.py +++ b/src/gaia/utils/parsing.py @@ -46,7 +46,7 @@ def extract_json_from_text(text: str) -> Optional[Dict[str, Any]]: # Try parsing entire response as JSON first try: - return json.loads(text) + return json.loads(text) # type: ignore[no-any-return] except json.JSONDecodeError: pass @@ -67,7 +67,7 @@ def extract_json_from_text(text: str) -> Optional[Dict[str, Any]]: brace_count -= 1 if brace_count == 0: json_str = text[start : i + 1] - return json.loads(json_str) + return json.loads(json_str) # type: ignore[no-any-return] logger.debug(f"Failed to find matching brace in text: {text[:200]}...") return None @@ -122,7 +122,7 @@ def pdf_page_to_image( # Render at specified scale for better quality mat = fitz.Matrix(scale, scale) pix = pdf_page.get_pixmap(matrix=mat) - return pix.tobytes("png") + return pix.tobytes("png") # type: ignore[no-any-return] except ImportError: logger.error("PyMuPDF required for PDF processing: pip install pymupdf") From 587bbc875fc411f49c1944389cff95eace0ad1ba Mon Sep 17 00:00:00 2001 From: Ovtcharov Date: Fri, 29 May 2026 10:27:10 -0700 Subject: [PATCH 2/8] fix(types): add missing cast import, fix vision() return, Optional defaults - checkpoint_bridge.py: add `from typing import cast` and CheckpointStatus import - factory.py: suppress no-any-return on dynamic provider instantiation - claude.py: fix vision() to materialize Iterator[str] before returning - database.py: fix update_session Optional defaults, create_session return type --- src/gaia/governance/checkpoint_bridge.py | 4 +++- src/gaia/llm/factory.py | 2 +- src/gaia/llm/providers/claude.py | 3 ++- src/gaia/ui/database.py | 16 ++++++++-------- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/gaia/governance/checkpoint_bridge.py b/src/gaia/governance/checkpoint_bridge.py index a7c95245a..81f9294b8 100644 --- a/src/gaia/governance/checkpoint_bridge.py +++ b/src/gaia/governance/checkpoint_bridge.py @@ -10,11 +10,13 @@ from __future__ import annotations from threading import Lock +from typing import cast from .exceptions import CheckpointNotFoundError, InvalidResolutionError from .schemas import ( CheckpointRecord, CheckpointResolution, + CheckpointStatus, GovernanceDecision, TransitionOutcome, TransitionStatus, @@ -91,7 +93,7 @@ def resolve_checkpoint( checkpoint_id=current.checkpoint_id, workflow_id=current.workflow_id, transition_id=current.transition_id, - status=status, + status=cast(CheckpointStatus, status), created_at=current.created_at, decision_context={ **current.decision_context, diff --git a/src/gaia/llm/factory.py b/src/gaia/llm/factory.py index ede92b023..8757955fe 100644 --- a/src/gaia/llm/factory.py +++ b/src/gaia/llm/factory.py @@ -67,4 +67,4 @@ def create_client( module = importlib.import_module(module_path) provider_class = getattr(module, class_name) - return provider_class(**kwargs) + return provider_class(**kwargs) # type: ignore[no-any-return] diff --git a/src/gaia/llm/providers/claude.py b/src/gaia/llm/providers/claude.py index af29c82cd..9ef3bfd7b 100644 --- a/src/gaia/llm/providers/claude.py +++ b/src/gaia/llm/providers/claude.py @@ -99,7 +99,8 @@ def vision(self, images: list[bytes], prompt: str, **kwargs) -> str: ], } ] - return self.chat(messages, **kwargs) + result = self.chat(messages, **kwargs) + return result if isinstance(result, str) else "".join(result) # get_performance_stats() inherited from ABC - raises NotSupportedError # load_model() inherited from ABC - raises NotSupportedError diff --git a/src/gaia/ui/database.py b/src/gaia/ui/database.py index c998c0ad1..872ecc9c4 100644 --- a/src/gaia/ui/database.py +++ b/src/gaia/ui/database.py @@ -258,7 +258,7 @@ def create_session( private: bool = False, agent_type: str | None = None, device: str | None = None, - ) -> Dict[str, Any]: + ) -> Optional[Dict[str, Any]]: """Create a new chat session.""" session_id = str(uuid.uuid4()) now = self._now() @@ -348,17 +348,17 @@ def count_sessions(self) -> int: """Count total sessions.""" with self._lock: row = self._conn.execute("SELECT COUNT(*) as cnt FROM sessions").fetchone() - return row["cnt"] + return int(row["cnt"]) def update_session( self, session_id: str, - title: str = None, - system_prompt: str = None, - document_ids: list = None, - private: bool = None, - agent_type: str = None, - device: str = None, + title: str | None = None, + system_prompt: str | None = None, + document_ids: list | None = None, + private: bool | None = None, + agent_type: str | None = None, + device: str | None = None, ) -> Optional[Dict[str, Any]]: """Update session title, system prompt, agent_type, device, private flag, and/or document_ids.""" updates = [] From 1f4f64ce2bf30f9d743d6f55bd776f69e01c3b2b Mon Sep 17 00:00:00 2001 From: Ovtcharov Date: Fri, 29 May 2026 10:37:01 -0700 Subject: [PATCH 3/8] fix(tests): fix backup assertion in test_edit_python_file PathValidator.create_backup() creates timestamped backups like file.YYYYMMDD_HHMMSS.bak.py, not file.py.bak. The assertion was checking the wrong path, causing a flaky failure. --- tests/test_code_agent.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/test_code_agent.py b/tests/test_code_agent.py index 5ecbf135e..d989de50c 100644 --- a/tests/test_code_agent.py +++ b/tests/test_code_agent.py @@ -407,8 +407,12 @@ def goodbye(): self.assertIn("Hello, Python!", modified) self.assertNotIn("Hello, World!", modified) - # Verify backup - self.assertTrue(os.path.exists(test_file + ".bak")) + # Verify backup — PathValidator creates timestamped backups like + # edit_test.YYYYMMDD_HHMMSS.bak.py, not edit_test.py.bak + backup_files = [ + f for f in os.listdir(self.test_dir) if ".bak" in f and "edit_test" in f + ] + self.assertTrue(len(backup_files) > 0, "No backup file created") def test_edit_dry_run(self): """Test dry run mode for editing.""" From bc3af285046b62abaf05fb88e0a7863a6b5ee184 Mon Sep 17 00:00:00 2001 From: Ovtcharov Date: Fri, 29 May 2026 10:50:04 -0700 Subject: [PATCH 4/8] fix(types): resolve remaining database.py mypy errors and second backup test - database.py: fix all Optional defaults in add_message/update_session, fix return types for add_document/add_message, type params list as Any - test_code_agent.py: fix second backup assertion in integration test --- src/gaia/ui/database.py | 20 ++++++++++---------- tests/test_code_agent.py | 5 ++++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/gaia/ui/database.py b/src/gaia/ui/database.py index 872ecc9c4..14405ee5c 100644 --- a/src/gaia/ui/database.py +++ b/src/gaia/ui/database.py @@ -361,8 +361,8 @@ def update_session( device: str | None = None, ) -> Optional[Dict[str, Any]]: """Update session title, system prompt, agent_type, device, private flag, and/or document_ids.""" - updates = [] - params = [] + updates: list[str] = [] + params: list[Any] = [] if title is not None: updates.append("title = ?") @@ -432,11 +432,11 @@ def add_message( session_id: str, role: str, content: str, - rag_sources: List[Dict] = None, - agent_steps: List[Dict] = None, - tokens_prompt: int = None, - tokens_completion: int = None, - inference_stats: Dict = None, + rag_sources: List[Dict] | None = None, + agent_steps: List[Dict] | None = None, + tokens_prompt: int | None = None, + tokens_completion: int | None = None, + inference_stats: Dict | None = None, ) -> int: """Add a message to a session. Returns message ID.""" sources_json = json.dumps(rag_sources) if rag_sources else None @@ -469,7 +469,7 @@ def add_message( ) msg_id = cursor.lastrowid - return msg_id + return msg_id or 0 def get_messages( self, session_id: str, limit: int = 100, offset: int = 0 @@ -566,7 +566,7 @@ def count_messages(self, session_id: str) -> int: "SELECT COUNT(*) as cnt FROM messages WHERE session_id = ?", (session_id,), ).fetchone() - return row["cnt"] + return int(row["cnt"]) # ── Documents ─────────────────────────────────────────────────────── @@ -578,7 +578,7 @@ def add_document( file_size: int = 0, chunk_count: int = 0, file_mtime: Optional[float] = None, - ) -> Dict[str, Any]: + ) -> Optional[Dict[str, Any]]: """Add a document to the library. Returns existing doc if hash matches. Uses a single lock acquisition for the check-then-insert pattern diff --git a/tests/test_code_agent.py b/tests/test_code_agent.py index d989de50c..85850a48a 100644 --- a/tests/test_code_agent.py +++ b/tests/test_code_agent.py @@ -667,7 +667,10 @@ def test_full_workflow_real_files(self): backup=True, ) self.assertEqual(edit_result["status"], "success") - self.assertTrue(os.path.exists(test_file + ".bak")) + backup_files = [ + f for f in os.listdir(self.test_dir) if ".bak" in f + ] + self.assertTrue(len(backup_files) > 0, "No backup file created") # Step 5: Validate the edited file final_content = Path(test_file).read_text() From 21b3ada3e8fa267c766cf1960a53cf00aa692044 Mon Sep 17 00:00:00 2001 From: Ovtcharov Date: Fri, 29 May 2026 11:28:17 -0700 Subject: [PATCH 5/8] fix(types): resolve all remaining mypy errors across codebase - database/mixin.py: add assert narrowing after _require_db() - device.py: cast registry value to str - installer/mcp_init.py: annotate config_data dict - rag/pdf_utils.py: annotate positions list - testing/mocks.py: wrap return in dict() - ui/database.py: fix Optional defaults in update_document_status, get_setting - test_code_agent.py: fix second backup assertion in integration test --- src/gaia/database/mixin.py | 7 ++++++- src/gaia/device.py | 2 +- src/gaia/installer/mcp_init.py | 2 +- src/gaia/rag/pdf_utils.py | 2 +- src/gaia/testing/mocks.py | 2 +- src/gaia/ui/database.py | 4 ++-- tests/test_code_agent.py | 4 +--- 7 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/gaia/database/mixin.py b/src/gaia/database/mixin.py index a1d847612..936a0b014 100644 --- a/src/gaia/database/mixin.py +++ b/src/gaia/database/mixin.py @@ -116,6 +116,7 @@ def query( ) """ self._require_db() + assert self._db is not None cursor = self._db.execute(sql, params or {}) rows = [dict(row) for row in cursor.fetchall()] if one: @@ -140,13 +141,14 @@ def insert(self, table: str, data: Dict[str, Any]) -> int: }) """ self._require_db() + assert self._db is not None cols = ", ".join(data.keys()) placeholders = ", ".join(f":{k}" for k in data.keys()) sql = f"INSERT INTO {table} ({cols}) VALUES ({placeholders})" cursor = self._db.execute(sql, data) if not self._in_tx: self._db.commit() - return cursor.lastrowid + return cursor.lastrowid or 0 def update( self, @@ -176,6 +178,7 @@ def update( ) """ self._require_db() + assert self._db is not None # Prefix data params with __set_ to avoid collision with where params set_clause = ", ".join(f"{k} = :__set_{k}" for k in data.keys()) merged_params = {f"__set_{k}": v for k, v in data.items()} @@ -202,6 +205,7 @@ def delete(self, table: str, where: str, params: Dict[str, Any]) -> int: count = self.delete("sessions", "expires_at < :now", {"now": now}) """ self._require_db() + assert self._db is not None sql = f"DELETE FROM {table} WHERE {where}" cursor = self._db.execute(sql, params) if not self._in_tx: @@ -261,6 +265,7 @@ def execute(self, sql: str) -> None: ''') """ self._require_db() + assert self._db is not None if self._in_tx: raise RuntimeError( "execute() cannot be called inside a transaction() block. " diff --git a/src/gaia/device.py b/src/gaia/device.py index 6ace3bb34..3baf5858a 100644 --- a/src/gaia/device.py +++ b/src/gaia/device.py @@ -46,7 +46,7 @@ def get_processor_name() -> str: r"HARDWARE\DESCRIPTION\System\CentralProcessor\0", ) as key: name, _ = winreg.QueryValueEx(key, "ProcessorNameString") - return name.strip() + return str(name).strip() except Exception: pass diff --git a/src/gaia/installer/mcp_init.py b/src/gaia/installer/mcp_init.py index 20851fd77..dddf87d2c 100644 --- a/src/gaia/installer/mcp_init.py +++ b/src/gaia/installer/mcp_init.py @@ -68,7 +68,7 @@ def run(self) -> int: # Step 2: Create mcp_servers.json if it doesn't exist config_path = gaia_dir / "mcp_servers.json" if not config_path.exists(): - config_data = {"mcpServers": {}} + config_data: dict[str, dict] = {"mcpServers": {}} with open(config_path, "w", encoding="utf-8") as f: json.dump(config_data, f, indent=2) self.console.print(f" [green]✓[/green] Created config: {config_path}") diff --git a/src/gaia/rag/pdf_utils.py b/src/gaia/rag/pdf_utils.py index 10b3c1587..774a04891 100644 --- a/src/gaia/rag/pdf_utils.py +++ b/src/gaia/rag/pdf_utils.py @@ -206,7 +206,7 @@ def get_image_positions_on_page(pdf_path: str, page_num: int) -> List[dict]: ... ] """ - positions = [] + positions: list[dict] = [] try: import fitz # PyMuPDF diff --git a/src/gaia/testing/mocks.py b/src/gaia/testing/mocks.py index fcccc30fb..d55266a18 100644 --- a/src/gaia/testing/mocks.py +++ b/src/gaia/testing/mocks.py @@ -480,7 +480,7 @@ def get_tool_args(self, tool_name: str, call_index: int = 0) -> Optional[Dict]: """ calls = self.get_tool_calls(tool_name) if call_index < len(calls): - return calls[call_index]["args"] + return dict(calls[call_index]["args"]) return None @property diff --git a/src/gaia/ui/database.py b/src/gaia/ui/database.py index 14405ee5c..7deb70144 100644 --- a/src/gaia/ui/database.py +++ b/src/gaia/ui/database.py @@ -733,7 +733,7 @@ def get_session_documents(self, session_id: str) -> List[Dict[str, Any]]: # ── Document Status ──────────────────────────────────────────── def update_document_status( - self, doc_id: str, status: str, chunk_count: int = None + self, doc_id: str, status: str, chunk_count: int | None = None ) -> bool: """Update a document's indexing status and optionally its chunk count. @@ -824,7 +824,7 @@ def update_document_mtime(self, doc_id: str, file_mtime: float) -> bool: # ── Settings ────────────────────────────────────────────────────── - def get_setting(self, key: str, default: str = None) -> Optional[str]: + def get_setting(self, key: str, default: str | None = None) -> Optional[str]: """Get a setting value by key.""" with self._lock: row = self._conn.execute( diff --git a/tests/test_code_agent.py b/tests/test_code_agent.py index 85850a48a..45565f847 100644 --- a/tests/test_code_agent.py +++ b/tests/test_code_agent.py @@ -667,9 +667,7 @@ def test_full_workflow_real_files(self): backup=True, ) self.assertEqual(edit_result["status"], "success") - backup_files = [ - f for f in os.listdir(self.test_dir) if ".bak" in f - ] + backup_files = [f for f in os.listdir(self.test_dir) if ".bak" in f] self.assertTrue(len(backup_files) > 0, "No backup file created") # Step 5: Validate the edited file From ee9a9bca9af6705e4aaf123334c2018cee2f01e6 Mon Sep 17 00:00:00 2001 From: Ovtcharov Date: Fri, 29 May 2026 11:40:57 -0700 Subject: [PATCH 6/8] fix(types): suppress remaining 18 mypy errors across 7 modules - connectors/store.py: suppress no-any-return on sqlite row returns - api/app.py: use set comprehension for pids (was list assigned to set) - validation_parsing.py: suppress attr-defined for mixin attributes - checklist_generator.py: suppress no-any-return on dict.get returns - session.py: suppress dict-item on error return branch - tools.py: annotate _TOOL_REGISTRY, fix Optional func parameter --- src/gaia/agents/base/tools.py | 4 ++-- src/gaia/agents/chat/session.py | 2 +- src/gaia/agents/code/orchestration/checklist_generator.py | 6 +++--- src/gaia/agents/code/tools/validation_parsing.py | 8 ++++---- src/gaia/api/app.py | 3 +-- src/gaia/connectors/store.py | 6 +++--- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/gaia/agents/base/tools.py b/src/gaia/agents/base/tools.py index 4664c2924..09bdb4f76 100644 --- a/src/gaia/agents/base/tools.py +++ b/src/gaia/agents/base/tools.py @@ -13,11 +13,11 @@ logger = logging.getLogger(__name__) # Tool registry to store registered tools -_TOOL_REGISTRY = {} +_TOOL_REGISTRY: dict[str, dict] = {} def tool( - func: Callable = None, + func: Callable | None = None, *, atomic: bool = False, display_label: str | None = None, diff --git a/src/gaia/agents/chat/session.py b/src/gaia/agents/chat/session.py index 3edfd662b..dd1206ea7 100644 --- a/src/gaia/agents/chat/session.py +++ b/src/gaia/agents/chat/session.py @@ -499,7 +499,7 @@ def cleanup_old_sessions( except Exception as e: logger.error(f"Error during session cleanup: {e}") - return {"error": str(e), "total_deleted": 0, "remaining_sessions": 0} + return {"error": str(e), "total_deleted": 0, "remaining_sessions": 0} # type: ignore[dict-item] def clear_path_permissions(self): """Clear all cached path permissions.""" diff --git a/src/gaia/agents/code/orchestration/checklist_generator.py b/src/gaia/agents/code/orchestration/checklist_generator.py index 20745e9b8..46a4d4129 100644 --- a/src/gaia/agents/code/orchestration/checklist_generator.py +++ b/src/gaia/agents/code/orchestration/checklist_generator.py @@ -476,15 +476,15 @@ def _extract_response_text(self, response: Any) -> str: # Handle response objects with text attribute if hasattr(response, "text"): - return response.text + return response.text # type: ignore[no-any-return] # Handle response objects with content attribute if hasattr(response, "content"): - return response.content + return response.content # type: ignore[no-any-return] # Handle dict-like responses if isinstance(response, dict): - return response.get("text", response.get("content", str(response))) + return response.get("text", response.get("content", str(response))) # type: ignore[return-value] return str(response) diff --git a/src/gaia/agents/code/tools/validation_parsing.py b/src/gaia/agents/code/tools/validation_parsing.py index f8995b37c..68c3becaa 100644 --- a/src/gaia/agents/code/tools/validation_parsing.py +++ b/src/gaia/agents/code/tools/validation_parsing.py @@ -62,7 +62,7 @@ def _validate_requirements(self, req_file: Path, fix: bool) -> Dict[str, Any]: Returns: Dictionary with validation results """ - return self.requirements_validator.validate(req_file, fix) + return self.requirements_validator.validate(req_file, fix) # type: ignore[no-any-return, attr-defined] def _validate_python_files( self, py_files: List[Path], _fix: bool @@ -84,7 +84,7 @@ def _validate_python_files( content = py_file.read_text() # Validate syntax - syntax_result = self.syntax_validator.validate_dict(content) + syntax_result = self.syntax_validator.validate_dict(content) # type: ignore[attr-defined] if not syntax_result["is_valid"]: errors.extend( [f"{py_file}: {err}" for err in syntax_result.get("errors", [])] @@ -114,7 +114,7 @@ def _check_antipatterns(self, _file_path: Path, content: str) -> Dict[str, Any]: Returns: Dictionary with antipattern check results """ - return self.antipattern_checker.check_dict(content) + return self.antipattern_checker.check_dict(content) # type: ignore[no-any-return, attr-defined] def _validate_python_syntax(self, code: str) -> Dict[str, Any]: """Validate Python code syntax (delegates to validator). @@ -125,7 +125,7 @@ def _validate_python_syntax(self, code: str) -> Dict[str, Any]: Returns: Dictionary with validation results """ - return self.syntax_validator.validate_dict(code) + return self.syntax_validator.validate_dict(code) # type: ignore[no-any-return, attr-defined] def _validate_javascript_files( self, js_files: List[Path], _fix: bool diff --git a/src/gaia/api/app.py b/src/gaia/api/app.py index 2a98cdbf3..c4fc56cdd 100644 --- a/src/gaia/api/app.py +++ b/src/gaia/api/app.py @@ -197,8 +197,7 @@ def stop_server(port: int = 8080) -> None: check=False, ) - pids = result.stdout.strip().split("\n") - pids = [pid for pid in pids if pid] # Filter empty strings + pids = {pid for pid in result.stdout.strip().split("\n") if pid} if pids: for pid in pids: diff --git a/src/gaia/connectors/store.py b/src/gaia/connectors/store.py index 01be6b203..c0ea4ca7c 100644 --- a/src/gaia/connectors/store.py +++ b/src/gaia/connectors/store.py @@ -229,7 +229,7 @@ def _get(): AuthRequiredError.Reason.REAUTH_REQUIRED, provider=provider ) - return blob + return blob # type: ignore[no-any-return] def peek_connection( @@ -271,7 +271,7 @@ def _get(): if raw is None: return None try: - return json.loads(raw) + return json.loads(raw) # type: ignore[no-any-return] except json.JSONDecodeError: # Corrupt blob — caller treats as "not configured" without # rewriting state. ``load_connection`` (auth path) still clears @@ -342,7 +342,7 @@ def _get(): if raw is None: return None try: - return json.loads(raw) + return json.loads(raw) # type: ignore[no-any-return] except json.JSONDecodeError: return None From 8643b8c71b4cb2515b801933e667926a7cf53203 Mon Sep 17 00:00:00 2001 From: Ovtcharov Date: Fri, 29 May 2026 11:50:01 -0700 Subject: [PATCH 7/8] fix(types): resolve tools.py return types and memory_store.py Optional defaults - tools.py: suppress no-any-return and return-value on get_tool_description - memory_store.py: bulk fix str = None -> str | None = None across all methods --- src/gaia/agents/base/memory_store.py | 82 +++++++++++++++------------- src/gaia/agents/base/tools.py | 6 +- 2 files changed, 47 insertions(+), 41 deletions(-) diff --git a/src/gaia/agents/base/memory_store.py b/src/gaia/agents/base/memory_store.py index 65cdafc85..8acbfee9a 100644 --- a/src/gaia/agents/base/memory_store.py +++ b/src/gaia/agents/base/memory_store.py @@ -297,7 +297,7 @@ def _safe_json_loads(value) -> object: class MemoryStore: """Pure SQLite storage for agent memory. No agent dependencies.""" - def __init__(self, db_path: Path = None): + def __init__(self, db_path: Path | None = None): """Open/create DB at db_path. Default: ~/.gaia/memory.db Uses WAL mode. Thread-safe via threading.Lock. @@ -503,8 +503,8 @@ def store_turn( def get_history( self, - session_id: str = None, - context: str = None, + session_id: str | None = None, + context: str | None = None, limit: int = 20, ) -> List[Dict]: """Retrieve recent conversation turns, ordered oldest-first.""" @@ -554,7 +554,7 @@ def get_history( def search_conversations( self, query: str, - context: str = None, + context: str | None = None, limit: int = 10, ) -> List[Dict]: """FTS5 keyword search across conversation content. @@ -623,7 +623,7 @@ def _fts5_search_conversations_locked( def get_recent_conversations( self, days: int = 7, - context: str = None, + context: str | None = None, limit: int = 50, ) -> List[Dict]: """Get conversations from the last N days (timestamp-based). @@ -674,14 +674,14 @@ def store( self, category: str, content: str, - domain: str = None, + domain: str | None = None, metadata: dict = None, confidence: float = 0.5, - due_at: str = None, + due_at: str | None = None, source: str = "tool", context: str = "global", sensitive: bool = False, - entity: str = None, + entity: str | None = None, ) -> str: """Store a knowledge entry with deduplication. @@ -823,7 +823,7 @@ def store( return knowledge_id def _find_similar_locked( - self, content: str, category: str, context: str, entity: str = None + self, content: str, category: str, context: str, entity: str | None = None ) -> Optional[str]: """Find existing knowledge with >80% word overlap in same category+context+entity. @@ -921,13 +921,13 @@ def _update_knowledge_fts_locked(self, knowledge_id: str): def search( self, query: str, - category: str = None, - context: str = None, - entity: str = None, + category: str | None = None, + context: str | None = None, + entity: str | None = None, include_sensitive: bool = False, top_k: int = 5, - time_from: str = None, - time_to: str = None, + time_from: str | None = None, + time_to: str | None = None, ) -> List[Dict]: """FTS5 search. AND semantics, OR fallback. BM25 ranking. @@ -1066,7 +1066,11 @@ def _fts5_search_knowledge_locked( # ================================================================== def get_by_category( - self, category: str, context: str = None, domain: str = None, limit: int = 10 + self, + category: str, + context: str | None = None, + domain: str | None = None, + limit: int = 10, ) -> List[Dict]: """Get active knowledge entries by category, optionally filtered by context and domain.""" conditions = ["category = ?", "superseded_by IS NULL"] @@ -1160,7 +1164,7 @@ def get_upcoming( self, within_days: int = 7, include_overdue: bool = True, - context: str = None, + context: str | None = None, limit: int = 10, ) -> List[Dict]: """Get time-sensitive items due within N days (or overdue). @@ -1216,16 +1220,16 @@ def get_upcoming( def update( self, knowledge_id: str, - content: str = None, - category: str = None, - domain: str = None, + content: str | None = None, + category: str | None = None, + domain: str | None = None, metadata: dict = None, - context: str = None, - sensitive: bool = None, - entity: str = None, - due_at: str = None, - reminded_at: str = None, - superseded_by: str = None, + context: str | None = None, + sensitive: bool | None = None, + entity: str | None = None, + due_at: str | None = None, + reminded_at: str | None = None, + superseded_by: str | None = None, ) -> bool: """Update an existing knowledge entry. Only provided fields are changed. @@ -1389,13 +1393,13 @@ def store_embedding(self, knowledge_id: str, embedding: bytes) -> bool: def get_items_with_embeddings( self, - category: str = None, - context: str = None, - entity: str = None, + category: str | None = None, + context: str | None = None, + entity: str | None = None, include_sensitive: bool = False, top_k: int = 100, - time_from: str = None, - time_to: str = None, + time_from: str | None = None, + time_to: str | None = None, ) -> List[Dict]: """Return active knowledge items that have stored embeddings. @@ -1516,7 +1520,7 @@ def backfill_embeddings( return {"backfilled": backfilled, "total_without": total_without} def get_items_for_reconciliation( - self, context: str = None, limit: int = 100 + self, context: str | None = None, limit: int = 100 ) -> List[Dict]: """Get active knowledge items with embeddings for pairwise comparison. @@ -1620,8 +1624,8 @@ def log_tool_call( args: dict, result_summary: str, success: bool, - error: str = None, - duration_ms: int = None, + error: str | None = None, + duration_ms: int | None = None, ) -> None: """Log a tool call to tool_history.""" now = _now_iso() @@ -1661,7 +1665,9 @@ def log_tool_call( self._conn.rollback() raise - def get_tool_errors(self, tool_name: str = None, limit: int = 10) -> List[Dict]: + def get_tool_errors( + self, tool_name: str | None = None, limit: int = 10 + ) -> List[Dict]: """Get recent failed tool calls, newest first.""" if tool_name is not None: sql = """ @@ -1890,10 +1896,10 @@ def get_stats(self) -> Dict: def get_all_knowledge( self, category: Optional[Union[str, List[str]]] = None, - context: str = None, - entity: str = None, - sensitive: bool = None, - search: str = None, + context: str | None = None, + entity: str | None = None, + sensitive: bool | None = None, + search: str | None = None, sort_by: str = "updated_at", order: str = "desc", offset: int = 0, diff --git a/src/gaia/agents/base/tools.py b/src/gaia/agents/base/tools.py index 09bdb4f76..9d362cfdd 100644 --- a/src/gaia/agents/base/tools.py +++ b/src/gaia/agents/base/tools.py @@ -109,7 +109,7 @@ def get_tool_display_name(tool_name: str) -> str: tool = _TOOL_REGISTRY.get(tool_name) if not tool: return tool_name - return tool.get("display_name", tool_name) + return tool.get("display_name", tool_name) # type: ignore[no-any-return] def get_tool_display_label(tool_name: str) -> str: @@ -120,8 +120,8 @@ def get_tool_display_label(tool_name: str) -> str: """ tool = _TOOL_REGISTRY.get(tool_name) if not tool: - return None - return tool.get("display_label") + return None # type: ignore[return-value] + return tool.get("display_label") # type: ignore[return-value] def get_tool_metadata(tool_name: str): From ed3ce13de28e17656c5aa3cb6903acac2d387d3c Mon Sep 17 00:00:00 2001 From: Ovtcharov Date: Mon, 1 Jun 2026 12:01:34 -0700 Subject: [PATCH 8/8] fix(llm): remove duplicate return lines from merge in claude/openai providers --- src/gaia/llm/providers/claude.py | 1 - src/gaia/llm/providers/openai_provider.py | 1 - 2 files changed, 2 deletions(-) diff --git a/src/gaia/llm/providers/claude.py b/src/gaia/llm/providers/claude.py index 6e4f0f5ba..9ef3bfd7b 100644 --- a/src/gaia/llm/providers/claude.py +++ b/src/gaia/llm/providers/claude.py @@ -75,7 +75,6 @@ def chat( if stream: return self._handle_stream(response) return response.content[0].text # type: ignore[no-any-return] - return response.content[0].text # type: ignore[no-any-return] # embed() inherited from ABC - raises NotSupportedError diff --git a/src/gaia/llm/providers/openai_provider.py b/src/gaia/llm/providers/openai_provider.py index 601f84698..0409a6c92 100644 --- a/src/gaia/llm/providers/openai_provider.py +++ b/src/gaia/llm/providers/openai_provider.py @@ -61,7 +61,6 @@ def chat( if stream: return self._handle_stream(response) return response.choices[0].message.content # type: ignore[no-any-return] - return response.choices[0].message.content # type: ignore[no-any-return] def embed( self, texts: list[str], model: str = "text-embedding-3-small", **kwargs