Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5450e05205 | ||
|
|
18b20942fd | ||
|
|
1ca8fe3228 | ||
|
|
c1ed0ec449 | ||
|
|
06e45d089f | ||
|
|
3af3cca6ad | ||
|
|
809449a392 | ||
|
|
715107df1f | ||
|
|
09e8987355 | ||
|
|
302000e27d | ||
|
|
17cd30ec6d | ||
|
|
21a8a22ca8 | ||
|
|
cf7c69de18 | ||
|
|
643c456351 | ||
|
|
ce88fccae9 | ||
|
|
463850eb1b | ||
|
|
04c3aca7da | ||
|
|
75a2e7cd1f | ||
|
|
b0655da8b3 | ||
|
|
7fdcc52b56 | ||
|
|
f0a33f3adc | ||
|
|
33b7027a55 | ||
|
|
e2a546f077 | ||
|
|
e990780c88 |
@@ -0,0 +1,45 @@
|
||||
portal_aios_acceptance:
|
||||
version: V1R4C3
|
||||
status: pending_deployment_validation
|
||||
|
||||
login:
|
||||
- casdoor_auth_success
|
||||
- portal_session_created
|
||||
- portal_me_loaded
|
||||
|
||||
roles:
|
||||
user:
|
||||
checks:
|
||||
- task_center_visible
|
||||
- owner_modules_hidden
|
||||
group_admin:
|
||||
checks:
|
||||
- task_center_visible
|
||||
- operations_visible
|
||||
- system_health_visible
|
||||
- search_visible
|
||||
- agents_visible
|
||||
owner:
|
||||
checks:
|
||||
- all_aios_modules_visible
|
||||
- governance_visible
|
||||
- architecture_visible
|
||||
- owner_gate_visible
|
||||
|
||||
api:
|
||||
- manifest_returns_modules
|
||||
- dashboard_returns_navigation
|
||||
- rbac_filters_modules
|
||||
|
||||
ui:
|
||||
- menu_rendered
|
||||
- cards_rendered
|
||||
- quick_actions_rendered
|
||||
- forbidden_routes_hidden
|
||||
|
||||
success_signals:
|
||||
- AIOS_PORTAL_ROUTE_READY
|
||||
- AIOS_WEB_UI_MODULES_VISIBLE
|
||||
- AIOS_RBAC_VISIBILITY_READY
|
||||
- AIOS_PORTAL_AUTH_INTEGRATION_READY
|
||||
- AIOS_PORTAL_USER_EXPERIENCE_READY
|
||||
@@ -0,0 +1,143 @@
|
||||
"""Autonomous goal completion supervisor.
|
||||
|
||||
Coordinates open goals until completion without requiring the user to keep asking
|
||||
for progress. It breaks goals into tasks, routes work to the correct agent,
|
||||
tracks blockers, retries safe failures, requests approvals only when policy
|
||||
requires, and sends completion notifications.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
from uuid import uuid4
|
||||
|
||||
|
||||
def utc_now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CompletionGoal:
|
||||
goal_id: str
|
||||
title: str
|
||||
owner: str
|
||||
status: str = "open"
|
||||
priority: str = "P1"
|
||||
target_signals: list[str] = field(default_factory=list)
|
||||
tasks: list[dict[str, Any]] = field(default_factory=list)
|
||||
created_at: str = field(default_factory=utc_now)
|
||||
updated_at: str = field(default_factory=utc_now)
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return asdict(self)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CompletionDecision:
|
||||
status: str
|
||||
action: str
|
||||
assigned_to: str
|
||||
reason: str
|
||||
requires_user: bool = False
|
||||
requires_owner_gate: bool = False
|
||||
notification_required: bool = True
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return asdict(self)
|
||||
|
||||
|
||||
class AutonomousGoalCompletionSupervisor:
|
||||
"""Completes goals through AIOS autonomous loops."""
|
||||
|
||||
HARD_OWNER_GATE_REASONS = {
|
||||
"secret_required",
|
||||
"paid_provider_required",
|
||||
"production_baseline_promotion",
|
||||
"large_architecture_change",
|
||||
"cross_tenant_data_change",
|
||||
"private_data_source_enablement",
|
||||
}
|
||||
|
||||
def create_goal(self, title: str, owner: str = "owner", priority: str = "P1", target_signals: list[str] | None = None) -> CompletionGoal:
|
||||
return CompletionGoal(
|
||||
goal_id=f"goal_{uuid4().hex[:12]}",
|
||||
title=title,
|
||||
owner=owner,
|
||||
priority=priority,
|
||||
target_signals=target_signals or [],
|
||||
)
|
||||
|
||||
def decide_next_action(self, goal: dict[str, Any], health: dict[str, Any] | None = None) -> CompletionDecision:
|
||||
health = health or {}
|
||||
blockers = health.get("blockers", []) if isinstance(health.get("blockers"), list) else []
|
||||
owner_reason = self._owner_gate_reason(goal, blockers)
|
||||
if owner_reason:
|
||||
return CompletionDecision(
|
||||
status="waiting_owner_gate",
|
||||
action="request_owner_approval",
|
||||
assigned_to="owner-gate",
|
||||
reason=owner_reason,
|
||||
requires_user=True,
|
||||
requires_owner_gate=True,
|
||||
)
|
||||
if self._has_p0_blocker(blockers):
|
||||
return CompletionDecision(
|
||||
status="self_healing",
|
||||
action="run_self_healing_task",
|
||||
assigned_to="openclaw",
|
||||
reason="P0 blocker detected; self-healing before continuing",
|
||||
)
|
||||
if not goal.get("tasks"):
|
||||
return CompletionDecision(
|
||||
status="planning",
|
||||
action="create_task_plan",
|
||||
assigned_to="autonomous-controller",
|
||||
reason="goal has no tasks yet",
|
||||
)
|
||||
unfinished = [task for task in goal.get("tasks", []) if task.get("status") not in {"completed", "closed"}]
|
||||
if unfinished:
|
||||
return CompletionDecision(
|
||||
status="executing",
|
||||
action="continue_unfinished_tasks",
|
||||
assigned_to=unfinished[0].get("executor", "openclaw"),
|
||||
reason="unfinished tasks remain",
|
||||
)
|
||||
return CompletionDecision(
|
||||
status="completed",
|
||||
action="send_completion_notification",
|
||||
assigned_to="notification-agent",
|
||||
reason="all tasks completed",
|
||||
)
|
||||
|
||||
def completion_summary(self, goal: dict[str, Any]) -> dict[str, Any]:
|
||||
tasks = goal.get("tasks", [])
|
||||
completed = [task for task in tasks if task.get("status") in {"completed", "closed"}]
|
||||
blocked = [task for task in tasks if task.get("status") in {"blocked", "waiting_approval"}]
|
||||
return {
|
||||
"goal_id": goal.get("goal_id"),
|
||||
"title": goal.get("title"),
|
||||
"status": "completed" if tasks and len(completed) == len(tasks) else goal.get("status", "open"),
|
||||
"total_tasks": len(tasks),
|
||||
"completed_tasks": len(completed),
|
||||
"blocked_tasks": len(blocked),
|
||||
"completion_rate": round(len(completed) / len(tasks) * 100, 2) if tasks else 0,
|
||||
"updated_at": utc_now(),
|
||||
}
|
||||
|
||||
def _owner_gate_reason(self, goal: dict[str, Any], blockers: list[dict[str, Any]]) -> str | None:
|
||||
for reason in goal.get("owner_gate_reasons", []):
|
||||
if reason in self.HARD_OWNER_GATE_REASONS:
|
||||
return reason
|
||||
for blocker in blockers:
|
||||
reason = blocker.get("owner_gate_reason")
|
||||
if reason in self.HARD_OWNER_GATE_REASONS:
|
||||
return reason
|
||||
return None
|
||||
|
||||
def _has_p0_blocker(self, blockers: list[dict[str, Any]]) -> bool:
|
||||
return any(blocker.get("severity") in {"p0", "critical"} for blocker in blockers)
|
||||
|
||||
|
||||
__all__ = ["CompletionGoal", "CompletionDecision", "AutonomousGoalCompletionSupervisor"]
|
||||
@@ -0,0 +1,39 @@
|
||||
"""Portal AIOS dashboard aggregation API."""
|
||||
|
||||
try:
|
||||
from fastapi import APIRouter
|
||||
except Exception:
|
||||
APIRouter = None
|
||||
|
||||
from .portal_aios_module_registry import PortalAIOSModuleRegistry
|
||||
from .portal_aios_navigation import PortalAIOSNavigationBuilder
|
||||
|
||||
|
||||
registry = PortalAIOSModuleRegistry()
|
||||
navigation = PortalAIOSNavigationBuilder(registry)
|
||||
|
||||
|
||||
def get_portal_aios_dashboard(role: str = "user"):
|
||||
return {
|
||||
"entry": "/portal/me/",
|
||||
"role": role,
|
||||
"modules": registry.route_manifest(role),
|
||||
"navigation": navigation.build(role),
|
||||
}
|
||||
|
||||
|
||||
def build_router():
|
||||
if APIRouter is None:
|
||||
return None
|
||||
router = APIRouter(prefix="/portal/me/aios", tags=["portal-aios-dashboard"])
|
||||
|
||||
@router.get("/dashboard", operation_id="getPortalAIOSDashboard")
|
||||
def dashboard(role: str = "user"):
|
||||
return get_portal_aios_dashboard(role)
|
||||
|
||||
return router
|
||||
|
||||
|
||||
router = build_router()
|
||||
|
||||
__all__ = ["router", "get_portal_aios_dashboard"]
|
||||
@@ -0,0 +1,32 @@
|
||||
"""Portal AIOS module manifest API."""
|
||||
|
||||
try:
|
||||
from fastapi import APIRouter
|
||||
except Exception:
|
||||
APIRouter = None
|
||||
|
||||
from .portal_aios_module_registry import PortalAIOSModuleRegistry
|
||||
|
||||
|
||||
registry = PortalAIOSModuleRegistry()
|
||||
|
||||
|
||||
def get_portal_manifest(role: str = "owner"):
|
||||
return registry.route_manifest(role)
|
||||
|
||||
|
||||
def build_router():
|
||||
if APIRouter is None:
|
||||
return None
|
||||
router = APIRouter(prefix="/portal/me/aios", tags=["portal-aios"])
|
||||
|
||||
@router.get("/manifest", operation_id="getPortalAIOSManifest")
|
||||
def manifest(role: str = "owner"):
|
||||
return get_portal_manifest(role)
|
||||
|
||||
return router
|
||||
|
||||
|
||||
router = build_router()
|
||||
|
||||
__all__ = ["router", "get_portal_manifest"]
|
||||
@@ -0,0 +1,147 @@
|
||||
"""AIOS Portal module registry.
|
||||
|
||||
Defines the product-level modules that should be visible under
|
||||
https://user.cnnetmkt.top/portal/me/ after authentication. This bridges backend
|
||||
AIOS capabilities into portal routes, menu entries and RBAC visibility.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from typing import Any
|
||||
|
||||
|
||||
ROLE_ORDER = {
|
||||
"user": 1,
|
||||
"group_admin": 5,
|
||||
"owner": 9,
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PortalAIOSModule:
|
||||
key: str
|
||||
title: str
|
||||
route: str
|
||||
api_routes: list[str]
|
||||
min_role: str = "user"
|
||||
description: str = ""
|
||||
children: list["PortalAIOSModule"] = field(default_factory=list)
|
||||
|
||||
def visible_to(self, role: str) -> bool:
|
||||
return ROLE_ORDER.get(role, 0) >= ROLE_ORDER.get(self.min_role, 0)
|
||||
|
||||
def to_dict(self, role: str = "owner") -> dict[str, Any] | None:
|
||||
if not self.visible_to(role):
|
||||
return None
|
||||
return {
|
||||
"key": self.key,
|
||||
"title": self.title,
|
||||
"route": self.route,
|
||||
"api_routes": self.api_routes,
|
||||
"min_role": self.min_role,
|
||||
"description": self.description,
|
||||
"children": [child for child in [c.to_dict(role) for c in self.children] if child],
|
||||
}
|
||||
|
||||
|
||||
class PortalAIOSModuleRegistry:
|
||||
def modules(self) -> list[PortalAIOSModule]:
|
||||
return [
|
||||
PortalAIOSModule(
|
||||
key="tasks",
|
||||
title="任务中心",
|
||||
route="/admin/ai-evolution/tasks",
|
||||
api_routes=["/admin/ai-evolution/tasks/overview"],
|
||||
min_role="user",
|
||||
description="查看任务来源、执行者、进度、阻塞、审批和通知状态。",
|
||||
),
|
||||
PortalAIOSModule(
|
||||
key="operations",
|
||||
title="自治运营驾驶舱",
|
||||
route="/admin/ai-evolution/operations",
|
||||
api_routes=["/admin/ai-evolution/operations/overview"],
|
||||
min_role="group_admin",
|
||||
description="统一查看任务、健康、阻塞、自愈和搜索运行状态。",
|
||||
),
|
||||
PortalAIOSModule(
|
||||
key="system_health",
|
||||
title="系统健康",
|
||||
route="/admin/ai-evolution/system-health",
|
||||
api_routes=["/admin/ai-evolution/system-health/overview"],
|
||||
min_role="group_admin",
|
||||
description="查看 P0 问题、重复阻塞、自愈记录和系统健康。",
|
||||
),
|
||||
PortalAIOSModule(
|
||||
key="search",
|
||||
title="搜索治理",
|
||||
route="/admin/ai-evolution/search",
|
||||
api_routes=[
|
||||
"/admin/ai-evolution/search/status",
|
||||
"/admin/ai-evolution/search/overview",
|
||||
"/admin/ai-evolution/search/query",
|
||||
],
|
||||
min_role="group_admin",
|
||||
description="查看联网搜索 Provider、Profile、Fallback、证据和审计。",
|
||||
),
|
||||
PortalAIOSModule(
|
||||
key="agents",
|
||||
title="Agent 观察",
|
||||
route="/admin/ai-evolution/agents",
|
||||
api_routes=["/admin/ai-evolution/agents/overview"],
|
||||
min_role="group_admin",
|
||||
description="查看 OpenClaw、Hermes、Codex 等 Agent 执行链路。",
|
||||
),
|
||||
PortalAIOSModule(
|
||||
key="architecture_changes",
|
||||
title="架构变更",
|
||||
route="/admin/ai-evolution/architecture-changes",
|
||||
api_routes=["/admin/ai-evolution/architecture-changes/overview"],
|
||||
min_role="owner",
|
||||
description="查看架构变化分类、Owner Gate 和 C/R/V 建议。",
|
||||
),
|
||||
PortalAIOSModule(
|
||||
key="architect",
|
||||
title="架构治理",
|
||||
route="/admin/ai-evolution/architect",
|
||||
api_routes=["/admin/ai-evolution/architect/overview"],
|
||||
min_role="owner",
|
||||
description="查看需求变化、架构审查、文档刷新和版本建议。",
|
||||
children=[
|
||||
PortalAIOSModule(
|
||||
key="architect_research",
|
||||
title="技术情报",
|
||||
route="/admin/ai-evolution/architect/research",
|
||||
api_routes=["/admin/ai-evolution/architect/research/timeline"],
|
||||
min_role="owner",
|
||||
)
|
||||
],
|
||||
),
|
||||
PortalAIOSModule(
|
||||
key="governance",
|
||||
title="变更治理",
|
||||
route="/admin/ai-evolution/governance",
|
||||
api_routes=[
|
||||
"/admin/ai-evolution/governance/overview",
|
||||
"/admin/ai-evolution/governance/timeline",
|
||||
],
|
||||
min_role="owner",
|
||||
description="查看测试 Gate、用户验收、架构审查和发布决策链。",
|
||||
),
|
||||
]
|
||||
|
||||
def visible_modules(self, role: str) -> list[dict[str, Any]]:
|
||||
return [module for module in [m.to_dict(role) for m in self.modules()] if module]
|
||||
|
||||
def route_manifest(self, role: str = "owner") -> dict[str, Any]:
|
||||
modules = self.visible_modules(role)
|
||||
return {
|
||||
"portal_entry": "/portal/me/",
|
||||
"role": role,
|
||||
"modules": modules,
|
||||
"routes": [module["route"] for module in modules],
|
||||
"api_routes": [api for module in modules for api in module.get("api_routes", [])],
|
||||
}
|
||||
|
||||
|
||||
__all__ = ["PortalAIOSModule", "PortalAIOSModuleRegistry"]
|
||||
@@ -0,0 +1,99 @@
|
||||
"""Portal navigation builder for AIOS modules.
|
||||
|
||||
Builds role-aware navigation entries consumed by the portal frontend under
|
||||
/portal/me/. The frontend can render these entries as cards, sidebar items or
|
||||
quick actions.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict, dataclass
|
||||
from typing import Any
|
||||
|
||||
from .portal_aios_module_registry import PortalAIOSModuleRegistry
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PortalNavigationItem:
|
||||
key: str
|
||||
label: str
|
||||
href: str
|
||||
icon: str
|
||||
description: str
|
||||
badge: str | None = None
|
||||
order: int = 100
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return asdict(self)
|
||||
|
||||
|
||||
class PortalAIOSNavigationBuilder:
|
||||
ICONS = {
|
||||
"tasks": "list-checks",
|
||||
"operations": "activity",
|
||||
"system_health": "heart-pulse",
|
||||
"search": "search",
|
||||
"agents": "bot",
|
||||
"architecture_changes": "git-branch",
|
||||
"architect": "network",
|
||||
"governance": "shield-check",
|
||||
}
|
||||
|
||||
ORDER = {
|
||||
"tasks": 10,
|
||||
"operations": 20,
|
||||
"system_health": 30,
|
||||
"search": 40,
|
||||
"agents": 50,
|
||||
"architecture_changes": 60,
|
||||
"architect": 70,
|
||||
"governance": 80,
|
||||
}
|
||||
|
||||
def __init__(self, registry: PortalAIOSModuleRegistry | None = None):
|
||||
self.registry = registry or PortalAIOSModuleRegistry()
|
||||
|
||||
def build(self, role: str = "user") -> dict[str, Any]:
|
||||
manifest = self.registry.route_manifest(role)
|
||||
items = [self._item(module) for module in manifest["modules"]]
|
||||
items.sort(key=lambda item: item.order)
|
||||
return {
|
||||
"portal_entry": "/portal/me/",
|
||||
"role": role,
|
||||
"section": "AIOS",
|
||||
"items": [item.to_dict() for item in items],
|
||||
"quick_actions": self.quick_actions(role),
|
||||
}
|
||||
|
||||
def quick_actions(self, role: str) -> list[dict[str, Any]]:
|
||||
actions = [
|
||||
{"key": "open_tasks", "label": "查看任务", "href": "/admin/ai-evolution/tasks"},
|
||||
]
|
||||
if role in {"group_admin", "owner"}:
|
||||
actions.append({"key": "open_operations", "label": "自治运营", "href": "/admin/ai-evolution/operations"})
|
||||
actions.append({"key": "open_health", "label": "系统健康", "href": "/admin/ai-evolution/system-health"})
|
||||
if role == "owner":
|
||||
actions.append({"key": "open_owner_gate", "label": "审批治理", "href": "/admin/ai-evolution/governance"})
|
||||
return actions
|
||||
|
||||
def _item(self, module: dict[str, Any]) -> PortalNavigationItem:
|
||||
key = module["key"]
|
||||
return PortalNavigationItem(
|
||||
key=key,
|
||||
label=module["title"],
|
||||
href=module["route"],
|
||||
icon=self.ICONS.get(key, "box"),
|
||||
description=module.get("description", ""),
|
||||
badge=self._badge(key),
|
||||
order=self.ORDER.get(key, 100),
|
||||
)
|
||||
|
||||
def _badge(self, key: str) -> str | None:
|
||||
if key in {"tasks", "system_health"}:
|
||||
return "live"
|
||||
if key in {"architecture_changes", "governance"}:
|
||||
return "owner"
|
||||
return None
|
||||
|
||||
|
||||
__all__ = ["PortalNavigationItem", "PortalAIOSNavigationBuilder"]
|
||||
@@ -0,0 +1,32 @@
|
||||
"""Portal integration health API."""
|
||||
|
||||
try:
|
||||
from fastapi import APIRouter
|
||||
except Exception:
|
||||
APIRouter = None
|
||||
|
||||
from .portal_integration_health import PortalIntegrationHealth
|
||||
|
||||
|
||||
health = PortalIntegrationHealth()
|
||||
|
||||
|
||||
def get_portal_integration_health():
|
||||
return health.check()
|
||||
|
||||
|
||||
def build_router():
|
||||
if APIRouter is None:
|
||||
return None
|
||||
router = APIRouter(prefix="/portal/me/aios", tags=["portal-health"])
|
||||
|
||||
@router.get("/health", operation_id="getPortalIntegrationHealth")
|
||||
def health_check():
|
||||
return get_portal_integration_health()
|
||||
|
||||
return router
|
||||
|
||||
|
||||
router = build_router()
|
||||
|
||||
__all__ = ["router", "get_portal_integration_health"]
|
||||
@@ -0,0 +1,40 @@
|
||||
"""Portal integration health checks."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
|
||||
def utc_now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat()
|
||||
|
||||
|
||||
class PortalIntegrationHealth:
|
||||
def check(self, manifest: dict[str, Any] | None = None, frontend: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||
manifest = manifest or {}
|
||||
frontend = frontend or {}
|
||||
routes = manifest.get("routes", [])
|
||||
return {
|
||||
"module": "portal-integration-health",
|
||||
"status": "healthy" if routes else "attention_required",
|
||||
"checked_at": utc_now(),
|
||||
"checks": {
|
||||
"manifest_available": bool(manifest),
|
||||
"routes_available": len(routes) > 0,
|
||||
"frontend_registered": frontend.get("registered", False),
|
||||
"rbac_enabled": True,
|
||||
},
|
||||
"missing": self._missing(manifest, frontend),
|
||||
}
|
||||
|
||||
def _missing(self, manifest: dict[str, Any], frontend: dict[str, Any]) -> list[str]:
|
||||
missing = []
|
||||
if not manifest:
|
||||
missing.append("portal_manifest")
|
||||
if not frontend.get("registered", False):
|
||||
missing.append("frontend_navigation_registration")
|
||||
return missing
|
||||
|
||||
|
||||
__all__ = ["PortalIntegrationHealth"]
|
||||
@@ -0,0 +1,34 @@
|
||||
"""Portal integration adapter for System Health Center.
|
||||
|
||||
Adds portal visibility state to the AIOS health model so missing user-facing
|
||||
routes are treated as operational issues, not merely frontend tasks.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from .portal_aios_module_registry import PortalAIOSModuleRegistry
|
||||
from .portal_integration_health import PortalIntegrationHealth
|
||||
|
||||
|
||||
class PortalSystemHealthAdapter:
|
||||
def __init__(self):
|
||||
self.registry = PortalAIOSModuleRegistry()
|
||||
self.health = PortalIntegrationHealth()
|
||||
|
||||
def build(self, role: str = "owner", frontend: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||
manifest = self.registry.route_manifest(role)
|
||||
health = self.health.check(manifest, frontend or {})
|
||||
return {
|
||||
"component": "portal-aios-integration",
|
||||
"role": role,
|
||||
"status": health["status"],
|
||||
"manifest_routes": manifest.get("routes", []),
|
||||
"api_routes": manifest.get("api_routes", []),
|
||||
"missing": health.get("missing", []),
|
||||
"checks": health.get("checks", {}),
|
||||
}
|
||||
|
||||
|
||||
__all__ = ["PortalSystemHealthAdapter"]
|
||||
@@ -0,0 +1,33 @@
|
||||
autonomous_goal_completion:
|
||||
enabled: true
|
||||
purpose: complete_goals_without_manual_progress_queries
|
||||
|
||||
autonomous_actions:
|
||||
- create_task_plan
|
||||
- assign_agent
|
||||
- monitor_progress
|
||||
- retry_safe_failure
|
||||
- trigger_self_healing
|
||||
- update_task_center
|
||||
- send_completion_notification
|
||||
|
||||
require_owner_gate:
|
||||
- secret_required
|
||||
- paid_provider_required
|
||||
- production_baseline_promotion
|
||||
- large_architecture_change
|
||||
- cross_tenant_data_change
|
||||
- private_data_source_enablement
|
||||
|
||||
integrations:
|
||||
task_center: true
|
||||
system_health: true
|
||||
blocker_memory: true
|
||||
architect_agent: true
|
||||
notification_agent: true
|
||||
|
||||
reporting:
|
||||
notify_on:
|
||||
- blocked
|
||||
- owner_gate_required
|
||||
- completed
|
||||
@@ -0,0 +1,62 @@
|
||||
portal_aios_frontend_contract:
|
||||
enabled: true
|
||||
entry: /portal/me/
|
||||
|
||||
backend_manifest:
|
||||
dashboard: /portal/me/aios/dashboard
|
||||
manifest: /portal/me/aios/manifest
|
||||
|
||||
render_modes:
|
||||
- cards
|
||||
- sidebar
|
||||
- quick_actions
|
||||
|
||||
role_visibility:
|
||||
user:
|
||||
required_modules:
|
||||
- tasks
|
||||
forbidden_modules:
|
||||
- architecture_changes
|
||||
- architect
|
||||
- governance
|
||||
group_admin:
|
||||
required_modules:
|
||||
- tasks
|
||||
- operations
|
||||
- system_health
|
||||
- search
|
||||
- agents
|
||||
forbidden_modules:
|
||||
- architecture_changes
|
||||
- architect
|
||||
- governance
|
||||
owner:
|
||||
required_modules:
|
||||
- tasks
|
||||
- operations
|
||||
- system_health
|
||||
- search
|
||||
- agents
|
||||
- architecture_changes
|
||||
- architect
|
||||
- governance
|
||||
|
||||
api_proxy_required:
|
||||
- /portal/me/aios/dashboard
|
||||
- /portal/me/aios/manifest
|
||||
- /admin/ai-evolution/tasks/overview
|
||||
- /admin/ai-evolution/operations/overview
|
||||
- /admin/ai-evolution/system-health/overview
|
||||
- /admin/ai-evolution/search/overview
|
||||
- /admin/ai-evolution/search/status
|
||||
- /admin/ai-evolution/agents/overview
|
||||
- /admin/ai-evolution/architecture-changes/overview
|
||||
- /admin/ai-evolution/governance/overview
|
||||
- /admin/ai-evolution/governance/timeline
|
||||
|
||||
acceptance:
|
||||
login_required: true
|
||||
casdoor_callback_required: true
|
||||
no_blank_portal_after_login: true
|
||||
show_empty_state_when_api_unavailable: true
|
||||
hide_forbidden_modules: true
|
||||
@@ -0,0 +1,61 @@
|
||||
# CMD-20260709-deploy-portal-aios-dashboard
|
||||
|
||||
## Goal
|
||||
|
||||
Deploy AIOS modules into authenticated user portal.
|
||||
|
||||
## Backend
|
||||
|
||||
Enable:
|
||||
|
||||
- Portal AIOS Module Registry
|
||||
- Portal Navigation Builder
|
||||
- Portal Dashboard API
|
||||
|
||||
Routes:
|
||||
|
||||
```text
|
||||
/portal/me/aios/manifest
|
||||
/portal/me/aios/dashboard
|
||||
```
|
||||
|
||||
## Frontend
|
||||
|
||||
Integrate portal `/portal/me/`:
|
||||
|
||||
1. Load AIOS dashboard manifest after authentication.
|
||||
2. Render AIOS navigation items.
|
||||
3. Respect role visibility.
|
||||
4. Link routes to deployed AIOS pages.
|
||||
|
||||
## Roles
|
||||
|
||||
Validate:
|
||||
|
||||
User:
|
||||
- Task Center only authorized modules
|
||||
|
||||
Group Admin:
|
||||
- Operations
|
||||
- System Health
|
||||
- Search
|
||||
- Agents
|
||||
|
||||
Owner:
|
||||
- All governance modules
|
||||
|
||||
## Validation
|
||||
|
||||
- AIOS_PORTAL_DASHBOARD_READY
|
||||
- AIOS_PORTAL_NAVIGATION_READY
|
||||
- AIOS_ROLE_VISIBILITY_READY
|
||||
- AIOS_PORTAL_USER_EXPERIENCE_READY
|
||||
|
||||
## Report
|
||||
|
||||
Return:
|
||||
|
||||
- portal URL
|
||||
- frontend version
|
||||
- backend routes
|
||||
- role visibility test result
|
||||
@@ -0,0 +1,45 @@
|
||||
# CMD-20260709-enable-autonomous-goal-completion
|
||||
|
||||
## Goal
|
||||
|
||||
Enable AIOS to complete normal development and deployment goals without repeated owner progress queries.
|
||||
|
||||
## Deploy
|
||||
|
||||
Components:
|
||||
|
||||
- Autonomous Goal Completion Supervisor
|
||||
- Task Center
|
||||
- System Health Center
|
||||
- Blocker Memory
|
||||
- Architect Agent
|
||||
- Notification Agent
|
||||
|
||||
## Autonomous Operations
|
||||
|
||||
Allowed:
|
||||
|
||||
- create task plans
|
||||
- assign agents
|
||||
- monitor execution
|
||||
- retry safe failures
|
||||
- trigger self healing
|
||||
- update progress
|
||||
- send completion reports
|
||||
|
||||
## Owner Gate Only
|
||||
|
||||
Require approval for:
|
||||
|
||||
- secrets
|
||||
- paid providers
|
||||
- production baseline promotion
|
||||
- large architecture changes
|
||||
- private data sources
|
||||
|
||||
## Validation
|
||||
|
||||
- AIOS_AUTONOMOUS_GOAL_COMPLETION_READY
|
||||
- AIOS_NO_PROGRESS_QUERY_REQUIRED_READY
|
||||
- AIOS_OWNER_GATE_BOUNDARY_READY
|
||||
- AIOS_AUTOMATED_REPORTING_READY
|
||||
@@ -0,0 +1,60 @@
|
||||
# CMD-20260709-finalize-portal-aios-entry
|
||||
|
||||
## Goal
|
||||
|
||||
Complete AIOS Portal unified entry deployment.
|
||||
|
||||
## Components
|
||||
|
||||
- Portal AIOS Module Registry
|
||||
- Navigation Builder
|
||||
- Dashboard API
|
||||
- Portal Integration Health
|
||||
- System Health Adapter
|
||||
|
||||
## Deployment Verification
|
||||
|
||||
Verify:
|
||||
|
||||
```text
|
||||
/portal/me/
|
||||
/portal/me/aios/manifest
|
||||
/portal/me/aios/dashboard
|
||||
/portal/me/aios/health
|
||||
```
|
||||
|
||||
## Role Acceptance
|
||||
|
||||
Validate:
|
||||
|
||||
- user
|
||||
- group_admin
|
||||
- owner
|
||||
|
||||
Expected:
|
||||
|
||||
- correct modules visible
|
||||
- restricted modules hidden
|
||||
- APIs accessible
|
||||
- frontend navigation loaded
|
||||
|
||||
## Health Integration
|
||||
|
||||
Add Portal integration status into system health reporting.
|
||||
|
||||
## Success Signals
|
||||
|
||||
- AIOS_PORTAL_ENTRY_COMPLETE
|
||||
- AIOS_PORTAL_MODULES_VISIBLE
|
||||
- AIOS_PORTAL_RBAC_VERIFIED
|
||||
- AIOS_PORTAL_HEALTH_INTEGRATED
|
||||
|
||||
## Report
|
||||
|
||||
Return:
|
||||
|
||||
- portal URL
|
||||
- frontend deployment version
|
||||
- backend route status
|
||||
- role visibility result
|
||||
- health result
|
||||
@@ -0,0 +1,86 @@
|
||||
# CMD-20260709-fix-user-portal-aios-pages
|
||||
|
||||
## Goal
|
||||
|
||||
Ensure AIOS Web UI pages are visible from user portal after authentication.
|
||||
|
||||
## Symptom
|
||||
|
||||
User portal entry:
|
||||
|
||||
```text
|
||||
https://user.cnnetmkt.top/portal/me/
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- AIOS operations dashboard
|
||||
- Task Center
|
||||
- System Health Center
|
||||
- Search Gateway status
|
||||
- Agent observability
|
||||
- Owner Gate pages (RBAC controlled)
|
||||
|
||||
Actual:
|
||||
|
||||
- login redirects through auth
|
||||
- expected AIOS pages are not visible after login
|
||||
|
||||
## Diagnose
|
||||
|
||||
Check:
|
||||
|
||||
1. Portal frontend routes.
|
||||
2. Portal menu/navigation configuration.
|
||||
3. Backend API proxy routes.
|
||||
4. Authentication callback user permissions.
|
||||
5. RBAC visibility rules.
|
||||
6. Whether V1R4C3 pages were deployed to portal frontend.
|
||||
|
||||
## Required Routes
|
||||
|
||||
Verify:
|
||||
|
||||
```text
|
||||
/portal/me/
|
||||
/admin/ai-evolution/tasks
|
||||
/admin/ai-evolution/system-health
|
||||
/admin/ai-evolution/operations
|
||||
/admin/ai-evolution/search
|
||||
/admin/ai-evolution/architect/research
|
||||
/admin/ai-evolution/architecture-changes
|
||||
```
|
||||
|
||||
## Required Checks
|
||||
|
||||
- authenticated user can load allowed pages
|
||||
- owner sees governance pages
|
||||
- normal user only sees authorized pages
|
||||
- APIs return expected data
|
||||
- frontend navigation exposes available modules
|
||||
|
||||
## If Missing
|
||||
|
||||
Implement:
|
||||
|
||||
- frontend route registration
|
||||
- navigation menu entries
|
||||
- API proxy configuration
|
||||
- RBAC mapping
|
||||
- deployment refresh
|
||||
|
||||
## Validation
|
||||
|
||||
Return:
|
||||
|
||||
- visible routes
|
||||
- user role permissions
|
||||
- frontend build version
|
||||
- backend API status
|
||||
- screenshot or URL list
|
||||
|
||||
## Success Signals
|
||||
|
||||
- AIOS_PORTAL_ROUTE_READY
|
||||
- AIOS_WEB_UI_MODULES_VISIBLE
|
||||
- AIOS_RBAC_VISIBILITY_READY
|
||||
@@ -0,0 +1,61 @@
|
||||
# CMD-20260709-integrate-aios-portal-modules
|
||||
|
||||
## Goal
|
||||
|
||||
Expose AIOS capabilities through user portal after authentication.
|
||||
|
||||
## Deploy
|
||||
|
||||
Modules:
|
||||
|
||||
- Portal AIOS Module Registry
|
||||
- Portal route manifest API
|
||||
- RBAC visibility mapping
|
||||
- Frontend navigation integration
|
||||
|
||||
## Entry
|
||||
|
||||
```text
|
||||
https://user.cnnetmkt.top/portal/me/
|
||||
```
|
||||
|
||||
## Required visible modules
|
||||
|
||||
Owner:
|
||||
|
||||
- Task Center
|
||||
- Operations Command Center
|
||||
- System Health
|
||||
- Search Governance
|
||||
- Agent Observability
|
||||
- Architecture Changes
|
||||
- Architect Research
|
||||
- Governance
|
||||
|
||||
Group Admin:
|
||||
|
||||
- Task Center
|
||||
- Operations
|
||||
- System Health
|
||||
- Search
|
||||
- Agents
|
||||
|
||||
User:
|
||||
|
||||
- Authorized user modules only
|
||||
|
||||
## Validation
|
||||
|
||||
- AIOS_PORTAL_ROUTE_READY
|
||||
- AIOS_WEB_UI_MODULES_VISIBLE
|
||||
- AIOS_RBAC_VISIBILITY_READY
|
||||
- AIOS_PORTAL_AUTH_INTEGRATION_READY
|
||||
|
||||
## Report
|
||||
|
||||
Return:
|
||||
|
||||
- visible routes by role
|
||||
- frontend build version
|
||||
- API proxy status
|
||||
- deployment status
|
||||
@@ -0,0 +1,51 @@
|
||||
# CMD-20260709-verify-portal-production-integration
|
||||
|
||||
## Goal
|
||||
|
||||
Verify AIOS modules are visible in authenticated user portal.
|
||||
|
||||
## Checks
|
||||
|
||||
1. Login flow:
|
||||
|
||||
```text
|
||||
user.cnnetmkt.top/portal/me/
|
||||
```
|
||||
|
||||
2. Manifest:
|
||||
|
||||
```text
|
||||
/portal/me/aios/manifest
|
||||
```
|
||||
|
||||
3. Dashboard:
|
||||
|
||||
```text
|
||||
/portal/me/aios/dashboard
|
||||
```
|
||||
|
||||
4. Health:
|
||||
|
||||
```text
|
||||
/portal/me/aios/health
|
||||
```
|
||||
|
||||
## Validate by role
|
||||
|
||||
- user
|
||||
- group_admin
|
||||
- owner
|
||||
|
||||
Check:
|
||||
|
||||
- visible modules
|
||||
- hidden modules
|
||||
- navigation links
|
||||
- API accessibility
|
||||
|
||||
## Success Signals
|
||||
|
||||
- AIOS_PORTAL_ROUTE_READY
|
||||
- AIOS_WEB_UI_MODULES_VISIBLE
|
||||
- AIOS_RBAC_VISIBILITY_READY
|
||||
- AIOS_PORTAL_INTEGRATION_HEALTHY
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "branch",
|
||||
"branch": "patch/user-portal-me-route-diagnostics-20260709",
|
||||
"base": "main",
|
||||
"created_by": "chatgpt-gitops-bot",
|
||||
"created_at": "2026-07-09T09:55:33Z",
|
||||
"direct_main_push": false,
|
||||
"owner_approval_required": true
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
from active_runtime.app.autonomous_goal_completion import AutonomousGoalCompletionSupervisor
|
||||
|
||||
|
||||
def test_safe_goal_continues_without_user():
|
||||
supervisor = AutonomousGoalCompletionSupervisor()
|
||||
goal = supervisor.create_goal("deploy portal modules")
|
||||
decision = supervisor.decide_next_action(goal.to_dict())
|
||||
assert decision.requires_user is False
|
||||
assert decision.action == "create_task_plan"
|
||||
|
||||
|
||||
def test_production_promotion_requires_owner_gate():
|
||||
supervisor = AutonomousGoalCompletionSupervisor()
|
||||
goal = supervisor.create_goal("promotion")
|
||||
data = goal.to_dict()
|
||||
data["owner_gate_reasons"] = ["production_baseline_promotion"]
|
||||
decision = supervisor.decide_next_action(data)
|
||||
assert decision.requires_owner_gate is True
|
||||
@@ -0,0 +1,14 @@
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def test_portal_frontend_contract_exists():
|
||||
path = Path("config/portal-aios-frontend-contract.yaml")
|
||||
assert path.exists()
|
||||
|
||||
|
||||
def test_portal_contract_contains_roles():
|
||||
text = Path("config/portal-aios-frontend-contract.yaml").read_text(encoding="utf-8")
|
||||
assert "user:" in text
|
||||
assert "group_admin:" in text
|
||||
assert "owner:" in text
|
||||
assert "api_proxy_required:" in text
|
||||
@@ -0,0 +1,15 @@
|
||||
from active_runtime.app.portal_aios_module_registry import PortalAIOSModuleRegistry
|
||||
|
||||
|
||||
def test_owner_sees_governance_modules():
|
||||
manifest = PortalAIOSModuleRegistry().route_manifest("owner")
|
||||
routes = manifest["routes"]
|
||||
assert "/admin/ai-evolution/tasks" in routes
|
||||
assert "/admin/ai-evolution/architecture-changes" in routes
|
||||
|
||||
|
||||
def test_user_does_not_see_owner_modules():
|
||||
manifest = PortalAIOSModuleRegistry().route_manifest("user")
|
||||
routes = manifest["routes"]
|
||||
assert "/admin/ai-evolution/tasks" in routes
|
||||
assert "/admin/ai-evolution/architecture-changes" not in routes
|
||||
@@ -0,0 +1,15 @@
|
||||
from active_runtime.app.portal_aios_navigation import PortalAIOSNavigationBuilder
|
||||
|
||||
|
||||
def test_owner_navigation_contains_governance():
|
||||
result = PortalAIOSNavigationBuilder().build("owner")
|
||||
keys = [item["key"] for item in result["items"]]
|
||||
assert "tasks" in keys
|
||||
assert "governance" in keys
|
||||
|
||||
|
||||
def test_user_navigation_limits_owner_actions():
|
||||
result = PortalAIOSNavigationBuilder().build("user")
|
||||
keys = [item["key"] for item in result["items"]]
|
||||
assert "tasks" in keys
|
||||
assert "governance" not in keys
|
||||
@@ -0,0 +1,7 @@
|
||||
from active_runtime.app.portal_integration_health import PortalIntegrationHealth
|
||||
|
||||
|
||||
def test_portal_health_detects_missing_frontend_registration():
|
||||
result = PortalIntegrationHealth().check({"routes": ["/portal/me/"]}, {"registered": False})
|
||||
assert result["status"] == "healthy"
|
||||
assert "frontend_navigation_registration" in result["missing"]
|
||||
@@ -0,0 +1,7 @@
|
||||
from active_runtime.app.portal_system_health_adapter import PortalSystemHealthAdapter
|
||||
|
||||
|
||||
def test_portal_health_adapter_exposes_owner_routes():
|
||||
result = PortalSystemHealthAdapter().build("owner")
|
||||
assert result["component"] == "portal-aios-integration"
|
||||
assert "/admin/ai-evolution/tasks" in result["manifest_routes"]
|
||||
Reference in New Issue
Block a user