From 400224a08958e395030e09a37c31e7765aef6f9d Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Fri, 11 Sep 2026 12:18:35 -0400 Subject: [PATCH] fix(ai): facade backend/tools/api.py (namespace packages, __init__ ignore) Le .gitignore exclut _*.py, donc backend/tools/__init__.py n'etait pas versionne et la CI echouait a l'import (unknown location). Remplacement par une facade api.py qui enregistre les outils et reexporte l'API publique. Tests adaptes. --- backend/tools/api.py | 53 +++++++++++++++++++++++++++++++++++ docs/AI_ARCHITECTURE_GUIDE.md | 4 ++- tests/test_tools.py | 2 +- 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 backend/tools/api.py diff --git a/backend/tools/api.py b/backend/tools/api.py new file mode 100644 index 0000000..f770b69 --- /dev/null +++ b/backend/tools/api.py @@ -0,0 +1,53 @@ +"""Public facade for the AI tool layer. + +Importing this module registers all built-in tools (via +``backend.tools.service``) and re-exports the public API. Consumers (agent +loop, MCP server, tests) should import from here rather than from individual +submodules. + +Note: ObsiGate uses implicit namespace packages (no tracked ``__init__.py``, +which ``.gitignore`` excludes via ``_*.py``), hence this explicit facade. +""" + +from backend.tools import service as _service # noqa: F401 (registers tools) +from backend.tools.context import ( + ToolConfirmationRequired, + ToolContext, + ToolError, + ToolMode, + ToolNotFoundError, + ToolPermissionError, + ToolRisk, + ToolScope, + ToolValidationError, + resolve_safe_path, +) +from backend.tools.registry import ( + ToolSpec, + call_tool, + get_tool, + get_tool_schemas, + list_tools, + tool, +) +from backend.tools.schemas import ToolResult + +__all__ = [ + "ToolConfirmationRequired", + "ToolContext", + "ToolError", + "ToolMode", + "ToolNotFoundError", + "ToolPermissionError", + "ToolResult", + "ToolRisk", + "ToolScope", + "ToolSpec", + "ToolValidationError", + "call_tool", + "get_tool", + "get_tool_schemas", + "list_tools", + "resolve_safe_path", + "tool", +] diff --git a/docs/AI_ARCHITECTURE_GUIDE.md b/docs/AI_ARCHITECTURE_GUIDE.md index 6c5ada3..59c7027 100644 --- a/docs/AI_ARCHITECTURE_GUIDE.md +++ b/docs/AI_ARCHITECTURE_GUIDE.md @@ -97,7 +97,7 @@ Extraire la logique métier des routes de `backend/main.py` vers des fonctions r ``` backend/tools/ -├── __init__.py +├── api.py # façade publique (enregistre les outils, réexporte l'API) ├── context.py # ToolContext (user, allowed_vaults, mode, confirmed) ├── registry.py # décorateur @tool(...) + schémas JSON ├── schemas.py # modèles Pydantic entrée/sortie @@ -105,6 +105,8 @@ backend/tools/ └── audit.py # journalisation des appels d'outils ``` +> ObsiGate utilise des **namespace packages** implicites (aucun `__init__.py` suivi — `.gitignore` exclut `_*.py`). La façade `api.py` joue le rôle de point d'entrée et déclenche l'enregistrement des outils. + ### 3.2 Couche 2 — Registry d'outils Chaque outil déclare : `name`, `description`, `parameters` (JSON Schema), `risk` (`read` | `write` | `dangerous`), `requires_confirmation` (bool), `scopes` (`in_app`, `mcp`). diff --git a/tests/test_tools.py b/tests/test_tools.py index 582800f..2debc83 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -10,7 +10,7 @@ from pathlib import Path import pytest -from backend.tools import ( +from backend.tools.api import ( ToolConfirmationRequired, ToolContext, ToolError,