feat(secrets): add @extensible decorator to secrets factory functions

Add @extensible decorator to all three secrets factory functions in helpers/secrets.py, enabling plugins to intercept or replace the SecretsManager instance returned by these functions. Decorated functions: - get_secrets_manager() - get_project_secrets_manager() - get_default_secrets_manager() This is the first consumer of the @extensible decorator. Extension discovery has been verified to work with agent=None (the common case for these functions) via subagents.get_paths() plugin path resolution. Motivating use case: OpenBao secrets backend plugin that replaces the default .env-based SecretsManager with an OpenBao KV v2 backed instance. No behavioral change for existing users - the decorator only adds extension hooks around the existing functions.

Deimos AI committed Mar 12, 2026 at 15:30 UTC a051732d86267f91d652c572c09e03b5d7d41d73
1 file changed +4
helpers/secrets.py
+4
@@ -8,6 +8,7 @@ from typing import Dict, Optional, List, Literal, Set, Callable, Tuple, TYPE_CHE
8 from dotenv.parser import parse_stream
9 from helpers.errors import RepairableException
10 from helpers import files
11 +from helpers.extension import extensible
12
13 if TYPE_CHECKING:
14 from agent import AgentContext
@@ -504,6 +505,7 @@ class SecretsManager:
505 return merged
506
507
508 +@extensible
509 def get_secrets_manager(context: "AgentContext|None" = None) -> SecretsManager:
510 from helpers import projects
511
@@ -523,6 +525,7 @@ def get_secrets_manager(context: "AgentContext|None" = None) -> SecretsManager:
525
526 return SecretsManager.get_instance(*secret_files)
527
528 +@extensible
529 def get_project_secrets_manager(project_name: str, merge_with_global: bool = False) -> SecretsManager:
530 from helpers import projects
531
@@ -537,5 +540,6 @@ def get_project_secrets_manager(project_name: str, merge_with_global: bool = Fal
540
541 return SecretsManager.get_instance(*secret_files)
542
543 +@extensible
544 def get_default_secrets_manager() -> SecretsManager:
545 return SecretsManager.get_instance()
\ No newline at end of file