Initial commit: a0_software_orchestrator v1.0
- Auto-Registration-Bug behoben (register_project/get_project_id/resolve_project Trennung) - 25 Tests gruen (Pytest) - block_compactor-Tool refactored (Option B: Soft-Check statt Hard-Block) - 4 Restbaustellen gefixt - DB-Schema: plugin_settings-Tabelle hinzugefuegt - 3 Schattenprojekte aus DB geloescht - Plan v3 + Refactor-Plan + Worklog dokumentiert
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
|
||||
"""External tool capability detection via dynamic plugin scanning."""
|
||||
import os
|
||||
import yaml
|
||||
from typing import Dict, Any, List
|
||||
|
||||
|
||||
def _get_active_plugins() -> List[str]:
|
||||
"""Scan all plugin roots for active plugins."""
|
||||
active_plugins = []
|
||||
plugin_roots = ["/a0/plugins", "/a0/usr/plugins"]
|
||||
|
||||
for root in plugin_roots:
|
||||
if not os.path.isdir(root):
|
||||
continue
|
||||
for plugin_name in os.listdir(root):
|
||||
plugin_dir = os.path.join(root, plugin_name)
|
||||
if not os.path.isdir(plugin_dir):
|
||||
continue
|
||||
|
||||
plugin_yaml = os.path.join(plugin_dir, "plugin.yaml")
|
||||
if not os.path.isfile(plugin_yaml):
|
||||
continue
|
||||
|
||||
# Check if plugin is active
|
||||
is_active = False
|
||||
if os.path.isfile(os.path.join(plugin_dir, ".toggle-1")):
|
||||
is_active = True
|
||||
elif os.path.isfile(os.path.join(plugin_dir, ".toggle-0")):
|
||||
is_active = False
|
||||
else:
|
||||
# No toggle files, check always_enabled
|
||||
try:
|
||||
with open(plugin_yaml, "r") as f:
|
||||
config = yaml.safe_load(f)
|
||||
if config and config.get("always_enabled", False):
|
||||
is_active = True
|
||||
except (yaml.YAMLError) as e:
|
||||
pass
|
||||
|
||||
if is_active:
|
||||
active_plugins.append(plugin_name)
|
||||
|
||||
return active_plugins
|
||||
|
||||
|
||||
def generate_capability_report(config: Dict[str, Any] = None) -> Dict[str, Any]:
|
||||
"""Generate a capability report for all actively registered tools."""
|
||||
active_plugins = _get_active_plugins()
|
||||
report = {}
|
||||
|
||||
for name in active_plugins:
|
||||
report[name] = {
|
||||
"available": True,
|
||||
"fallback": "plugin is active",
|
||||
}
|
||||
|
||||
# Add a few standard tools not represented as plugins if they exist in config
|
||||
if config:
|
||||
tools_config = config.get("external_tools", {})
|
||||
for name, cfg in tools_config.items():
|
||||
if name not in report:
|
||||
report[name] = {
|
||||
"available": False,
|
||||
"fallback": cfg.get("fallback", "not available"),
|
||||
}
|
||||
|
||||
return report
|
||||
|
||||
|
||||
def check_tool(tool_name: str) -> Dict[str, Any]:
|
||||
"""Return availability for one plugin/tool capability name."""
|
||||
active_plugins = _get_active_plugins()
|
||||
if tool_name in active_plugins:
|
||||
return {"available": True, "fallback": "plugin is active"}
|
||||
# Also match by declared tool name inside active plugin manifests.
|
||||
for plugin_name in active_plugins:
|
||||
plugin_dir = os.path.join("/a0/usr/plugins", plugin_name)
|
||||
plugin_yaml = os.path.join(plugin_dir, "plugin.yaml")
|
||||
try:
|
||||
with open(plugin_yaml, "r", encoding="utf-8") as f:
|
||||
config = yaml.safe_load(f) or {}
|
||||
for tool in config.get("tools", []) or []:
|
||||
if tool.get("name") == tool_name:
|
||||
return {"available": True, "fallback": f"declared by plugin {plugin_name}"}
|
||||
except Exception:
|
||||
continue
|
||||
return {"available": False, "fallback": "not active or not declared"}
|
||||
Reference in New Issue
Block a user