feat(governance): 接入三 Agent 佈建布局
This commit is contained in:
@@ -35,70 +35,73 @@ from pydantic import BaseModel, Field
|
||||
|
||||
from src.core.logging import get_logger
|
||||
from src.core.sse import get_publisher
|
||||
from src.services.agent_market_governance_snapshot import (
|
||||
load_latest_agent_market_governance_snapshot,
|
||||
)
|
||||
from src.services.agent_service import (
|
||||
AgentService,
|
||||
TaskState,
|
||||
get_agent_service,
|
||||
)
|
||||
from src.services.ai_agent_automation_backlog_snapshot import (
|
||||
load_latest_ai_agent_automation_backlog_snapshot,
|
||||
)
|
||||
from src.services.ai_agent_automation_inventory_snapshot import (
|
||||
load_latest_ai_agent_automation_inventory_snapshot,
|
||||
)
|
||||
from src.services.agent_market_governance_snapshot import (
|
||||
load_latest_agent_market_governance_snapshot,
|
||||
from src.services.ai_agent_deployment_layout import (
|
||||
load_latest_ai_agent_deployment_layout,
|
||||
)
|
||||
from src.services.backup_dr_target_inventory import (
|
||||
load_latest_backup_dr_target_inventory,
|
||||
from src.services.ai_provider_route_matrix import (
|
||||
load_latest_ai_provider_route_matrix,
|
||||
)
|
||||
from src.services.backup_dr_readiness_matrix import (
|
||||
load_latest_backup_dr_readiness_matrix,
|
||||
)
|
||||
from src.services.backup_dr_target_inventory import (
|
||||
load_latest_backup_dr_target_inventory,
|
||||
)
|
||||
from src.services.backup_notification_policy import (
|
||||
load_latest_backup_notification_policy,
|
||||
)
|
||||
from src.services.backup_restore_drill_approval_package_template import (
|
||||
load_latest_backup_restore_drill_approval_package_template,
|
||||
)
|
||||
from src.services.offsite_escrow_readiness_status import (
|
||||
load_latest_offsite_escrow_readiness_status,
|
||||
)
|
||||
from src.services.runtime_surface_inventory import (
|
||||
load_latest_runtime_surface_inventory,
|
||||
)
|
||||
from src.services.gitea_workflow_runner_health import (
|
||||
load_latest_gitea_workflow_runner_health,
|
||||
)
|
||||
from src.services.observability_contract_matrix import (
|
||||
load_latest_observability_contract_matrix,
|
||||
)
|
||||
from src.services.ai_provider_route_matrix import (
|
||||
load_latest_ai_provider_route_matrix,
|
||||
)
|
||||
from src.services.service_health_gap_matrix import (
|
||||
load_latest_service_health_gap_matrix,
|
||||
)
|
||||
from src.services.service_health_failure_notification_policy import (
|
||||
load_latest_service_health_failure_notification_policy,
|
||||
)
|
||||
from src.services.package_supply_chain_inventory import (
|
||||
load_latest_package_supply_chain_inventory,
|
||||
)
|
||||
from src.services.javascript_package_inventory import (
|
||||
load_latest_javascript_package_inventory,
|
||||
)
|
||||
from src.services.docker_build_surface_inventory import (
|
||||
load_latest_docker_build_surface_inventory,
|
||||
from src.services.dependency_drift_check_plan import (
|
||||
load_latest_dependency_drift_check_plan,
|
||||
)
|
||||
from src.services.dependency_risk_policy import (
|
||||
load_latest_dependency_risk_policy,
|
||||
)
|
||||
from src.services.dependency_drift_check_plan import (
|
||||
load_latest_dependency_drift_check_plan,
|
||||
)
|
||||
from src.services.dependency_upgrade_approval_package_template import (
|
||||
load_latest_dependency_upgrade_approval_package_template,
|
||||
)
|
||||
from src.services.agent_service import (
|
||||
AgentService,
|
||||
TaskState,
|
||||
get_agent_service,
|
||||
from src.services.docker_build_surface_inventory import (
|
||||
load_latest_docker_build_surface_inventory,
|
||||
)
|
||||
from src.services.gitea_workflow_runner_health import (
|
||||
load_latest_gitea_workflow_runner_health,
|
||||
)
|
||||
from src.services.javascript_package_inventory import (
|
||||
load_latest_javascript_package_inventory,
|
||||
)
|
||||
from src.services.observability_contract_matrix import (
|
||||
load_latest_observability_contract_matrix,
|
||||
)
|
||||
from src.services.offsite_escrow_readiness_status import (
|
||||
load_latest_offsite_escrow_readiness_status,
|
||||
)
|
||||
from src.services.package_supply_chain_inventory import (
|
||||
load_latest_package_supply_chain_inventory,
|
||||
)
|
||||
from src.services.runtime_surface_inventory import (
|
||||
load_latest_runtime_surface_inventory,
|
||||
)
|
||||
from src.services.service_health_failure_notification_policy import (
|
||||
load_latest_service_health_failure_notification_policy,
|
||||
)
|
||||
from src.services.service_health_gap_matrix import (
|
||||
load_latest_service_health_gap_matrix,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/agents", tags=["Agent Teams"])
|
||||
@@ -494,6 +497,33 @@ async def get_automation_backlog_snapshot() -> dict[str, Any]:
|
||||
) from exc
|
||||
|
||||
|
||||
@router.get(
|
||||
"/agent-deployment-layout",
|
||||
response_model=dict[str, Any],
|
||||
summary="取得 AI Agent 佈建布局快照",
|
||||
description=(
|
||||
"讀取最新已提交的 OpenClaw / Hermes / NemoTron 佈建布局快照;"
|
||||
"此端點不部署 Agent、不呼叫外部模型、不送 Telegram、不碰 DB/Redis、不讀 Secret payload、"
|
||||
"不批准 SDK/API/shadow/canary/生產路由或主機變更。"
|
||||
),
|
||||
)
|
||||
async def get_agent_deployment_layout() -> dict[str, Any]:
|
||||
"""Return the latest read-only AI Agent deployment layout snapshot."""
|
||||
try:
|
||||
return await asyncio.to_thread(load_latest_ai_agent_deployment_layout)
|
||||
except FileNotFoundError as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=str(exc),
|
||||
) from exc
|
||||
except (json.JSONDecodeError, ValueError) as exc:
|
||||
logger.error("ai_agent_deployment_layout_invalid", error=str(exc))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="AI Agent 佈建布局快照無效",
|
||||
) from exc
|
||||
|
||||
|
||||
@router.get(
|
||||
"/runtime-surface-inventory",
|
||||
response_model=dict[str, Any],
|
||||
|
||||
135
apps/api/src/services/ai_agent_deployment_layout.py
Normal file
135
apps/api/src/services/ai_agent_deployment_layout.py
Normal file
@@ -0,0 +1,135 @@
|
||||
"""
|
||||
AI Agent deployment layout snapshot.
|
||||
|
||||
Loads the latest committed, read-only layout for OpenClaw, Hermes, and
|
||||
NemoTron across hosts, packages, tools, services, projects, web surfaces,
|
||||
learning loops, and Telegram notification boundaries. This module never
|
||||
deploys agents, sends Telegram messages, calls providers, or approves writes.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from src.services.snapshot_paths import default_evaluations_dir
|
||||
|
||||
_DEFAULT_EVALUATIONS_DIR = default_evaluations_dir(Path(__file__))
|
||||
_SNAPSHOT_PATTERN = "ai_agent_deployment_layout_*.json"
|
||||
_SCHEMA_VERSION = "ai_agent_deployment_layout_v1"
|
||||
|
||||
|
||||
def load_latest_ai_agent_deployment_layout(
|
||||
evaluations_dir: Path | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Load the newest committed AI Agent deployment layout snapshot."""
|
||||
directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR
|
||||
candidates = sorted(directory.glob(_SNAPSHOT_PATTERN))
|
||||
if not candidates:
|
||||
raise FileNotFoundError(f"no AI Agent deployment layout snapshots found in {directory}")
|
||||
|
||||
latest = candidates[-1]
|
||||
with latest.open(encoding="utf-8") as handle:
|
||||
payload = json.load(handle)
|
||||
|
||||
if not isinstance(payload, dict):
|
||||
raise ValueError(f"{latest}: expected JSON object")
|
||||
_require_schema(payload, _SCHEMA_VERSION, str(latest))
|
||||
_require_read_only_layout(payload, str(latest))
|
||||
_require_rollup_consistency(payload, str(latest))
|
||||
_require_frontend_redaction(payload, str(latest))
|
||||
_require_target_boundaries(payload, str(latest))
|
||||
return payload
|
||||
|
||||
|
||||
def _require_schema(payload: dict[str, Any], expected: str, label: str) -> None:
|
||||
actual = payload.get("schema_version")
|
||||
if actual != expected:
|
||||
raise ValueError(f"{label}: expected schema_version={expected}, got {actual!r}")
|
||||
|
||||
|
||||
def _require_read_only_layout(payload: dict[str, Any], label: str) -> None:
|
||||
program_status = payload.get("program_status") or {}
|
||||
if program_status.get("read_only_mode") is not True:
|
||||
raise ValueError(f"{label}: program_status.read_only_mode must be true")
|
||||
if program_status.get("deployment_authority") != "layout_only_no_runtime_deploy":
|
||||
raise ValueError(f"{label}: deployment_authority must stay layout_only_no_runtime_deploy")
|
||||
|
||||
boundaries = payload.get("approval_boundaries") or {}
|
||||
blocked_flags = {
|
||||
"sdk_installation_allowed",
|
||||
"paid_api_call_allowed",
|
||||
"shadow_or_canary_allowed",
|
||||
"production_routing_allowed",
|
||||
"destructive_operation_allowed",
|
||||
"secret_plaintext_allowed",
|
||||
"autonomous_host_mutation_allowed",
|
||||
"telegram_direct_send_allowed",
|
||||
}
|
||||
allowed = sorted(flag for flag in blocked_flags if boundaries.get(flag) is not False)
|
||||
if allowed:
|
||||
raise ValueError(f"{label}: approval boundaries must remain false: {allowed}")
|
||||
|
||||
|
||||
def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None:
|
||||
targets = payload.get("deployment_targets") or []
|
||||
rollups = payload.get("rollups") or {}
|
||||
|
||||
if rollups.get("total_targets") != len(targets):
|
||||
raise ValueError(f"{label}: rollups.total_targets must match deployment_targets")
|
||||
if rollups.get("by_domain") != _count_by(targets, "domain_id"):
|
||||
raise ValueError(f"{label}: rollups.by_domain must match deployment_targets")
|
||||
if rollups.get("by_primary_agent") != _count_by(targets, "primary_agent"):
|
||||
raise ValueError(f"{label}: rollups.by_primary_agent must match deployment_targets")
|
||||
if rollups.get("by_deployment_state") != _count_by(targets, "deployment_state"):
|
||||
raise ValueError(f"{label}: rollups.by_deployment_state must match deployment_targets")
|
||||
if rollups.get("by_telegram_policy") != _count_by(targets, "telegram_policy"):
|
||||
raise ValueError(f"{label}: rollups.by_telegram_policy must match deployment_targets")
|
||||
|
||||
blocked_target_ids = sorted(
|
||||
target.get("target_id")
|
||||
for target in targets
|
||||
if target.get("deployment_state") == "blocked_by_gate"
|
||||
or target.get("automation_level") == "blocked"
|
||||
)
|
||||
if sorted(rollups.get("blocked_target_ids") or []) != blocked_target_ids:
|
||||
raise ValueError(f"{label}: rollups.blocked_target_ids must match blocked targets")
|
||||
|
||||
|
||||
def _require_frontend_redaction(payload: dict[str, Any], label: str) -> None:
|
||||
redaction = ((payload.get("collaboration_contract") or {}).get("frontend_redaction") or {})
|
||||
if redaction.get("operator_conversation_display_allowed") is not False:
|
||||
raise ValueError(f"{label}: operator conversation display must stay false")
|
||||
if redaction.get("agent_private_reasoning_display_allowed") is not False:
|
||||
raise ValueError(f"{label}: agent private reasoning display must stay false")
|
||||
|
||||
|
||||
def _require_target_boundaries(payload: dict[str, Any], label: str) -> None:
|
||||
targets = payload.get("deployment_targets") or []
|
||||
missing = [
|
||||
target.get("target_id")
|
||||
for target in targets
|
||||
if not target.get("approval_gate")
|
||||
or not target.get("telegram_policy")
|
||||
or not target.get("communication_channels")
|
||||
]
|
||||
if missing:
|
||||
raise ValueError(f"{label}: deployment targets missing boundary fields: {sorted(missing)}")
|
||||
|
||||
invalid_nemotron_runtime = [
|
||||
target.get("target_id")
|
||||
for target in targets
|
||||
if target.get("primary_agent") == "nemotron"
|
||||
and target.get("automation_level") not in {"observe_only", "blocked"}
|
||||
]
|
||||
if invalid_nemotron_runtime:
|
||||
raise ValueError(f"{label}: Nemotron targets must stay observe_only or blocked")
|
||||
|
||||
|
||||
def _count_by(items: list[dict[str, Any]], key: str) -> dict[str, int]:
|
||||
counts: dict[str, int] = {}
|
||||
for item in items:
|
||||
value = item.get(key)
|
||||
counts[value] = counts.get(value, 0) + 1
|
||||
return counts
|
||||
186
apps/api/tests/test_ai_agent_deployment_layout.py
Normal file
186
apps/api/tests/test_ai_agent_deployment_layout.py
Normal file
@@ -0,0 +1,186 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from src.services.ai_agent_deployment_layout import (
|
||||
load_latest_ai_agent_deployment_layout,
|
||||
)
|
||||
|
||||
|
||||
def test_load_latest_ai_agent_deployment_layout_reads_committed_snapshot():
|
||||
data = load_latest_ai_agent_deployment_layout()
|
||||
|
||||
assert data["schema_version"] == "ai_agent_deployment_layout_v1"
|
||||
assert data["program_status"]["read_only_mode"] is True
|
||||
assert data["program_status"]["deployment_authority"] == "layout_only_no_runtime_deploy"
|
||||
assert data["rollups"]["total_targets"] == len(data["deployment_targets"]) == 42
|
||||
assert data["rollups"]["by_primary_agent"]["openclaw"] == 17
|
||||
assert data["rollups"]["by_primary_agent"]["hermes"] == 23
|
||||
assert data["rollups"]["by_primary_agent"]["nemotron"] == 2
|
||||
assert data["rollups"]["blocked_target_ids"] == [
|
||||
"host_120",
|
||||
"nemotron_replay_pipeline",
|
||||
]
|
||||
assert data["approval_boundaries"]["telegram_direct_send_allowed"] is False
|
||||
assert data["approval_boundaries"]["production_routing_allowed"] is False
|
||||
assert data["collaboration_contract"]["frontend_redaction"]["operator_conversation_display_allowed"] is False
|
||||
|
||||
nemotron_targets = [
|
||||
target for target in data["deployment_targets"] if target["primary_agent"] == "nemotron"
|
||||
]
|
||||
assert {target["automation_level"] for target in nemotron_targets} <= {"observe_only", "blocked"}
|
||||
|
||||
|
||||
def test_load_latest_ai_agent_deployment_layout_rejects_runtime_authority(tmp_path):
|
||||
snapshot = _snapshot()
|
||||
snapshot["approval_boundaries"]["production_routing_allowed"] = True
|
||||
(tmp_path / "ai_agent_deployment_layout_2026-06-11.json").write_text(
|
||||
json.dumps(snapshot),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match="approval boundaries"):
|
||||
load_latest_ai_agent_deployment_layout(tmp_path)
|
||||
|
||||
|
||||
def test_load_latest_ai_agent_deployment_layout_rejects_rollup_mismatch(tmp_path):
|
||||
snapshot = _snapshot()
|
||||
snapshot["rollups"]["by_primary_agent"]["openclaw"] = 99
|
||||
(tmp_path / "ai_agent_deployment_layout_2026-06-11.json").write_text(
|
||||
json.dumps(snapshot),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match="by_primary_agent"):
|
||||
load_latest_ai_agent_deployment_layout(tmp_path)
|
||||
|
||||
|
||||
def test_load_latest_ai_agent_deployment_layout_rejects_nemotron_runtime(tmp_path):
|
||||
snapshot = _snapshot()
|
||||
snapshot["deployment_targets"][0]["primary_agent"] = "nemotron"
|
||||
snapshot["deployment_targets"][0]["automation_level"] = "hitl_execute_after_approval"
|
||||
snapshot["rollups"]["by_primary_agent"] = {"nemotron": 1}
|
||||
(tmp_path / "ai_agent_deployment_layout_2026-06-11.json").write_text(
|
||||
json.dumps(snapshot),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match="Nemotron targets"):
|
||||
load_latest_ai_agent_deployment_layout(tmp_path)
|
||||
|
||||
|
||||
def _snapshot() -> dict:
|
||||
return {
|
||||
"schema_version": "ai_agent_deployment_layout_v1",
|
||||
"generated_at": "2026-06-11T18:20:00+08:00",
|
||||
"program_status": {
|
||||
"overall_completion_percent": 10,
|
||||
"current_priority": "P1",
|
||||
"current_task_id": "P1-401",
|
||||
"next_task_id": "P1-402",
|
||||
"read_only_mode": True,
|
||||
"deployment_authority": "layout_only_no_runtime_deploy",
|
||||
},
|
||||
"agent_contracts": [
|
||||
{
|
||||
"agent_id": "openclaw",
|
||||
"display_name": "OpenClaw",
|
||||
"primary_specialty": "生產仲裁",
|
||||
"deployment_lane": "production_decision_core",
|
||||
"allowed_autonomy": ["只讀診斷"],
|
||||
"must_delegate_to": ["Hermes"],
|
||||
"blocked_actions": ["production_write"],
|
||||
"learning_scope": ["incident"],
|
||||
},
|
||||
{
|
||||
"agent_id": "hermes",
|
||||
"display_name": "Hermes",
|
||||
"primary_specialty": "治理",
|
||||
"deployment_lane": "governance",
|
||||
"allowed_autonomy": ["只讀盤點"],
|
||||
"must_delegate_to": ["OpenClaw"],
|
||||
"blocked_actions": ["production_write"],
|
||||
"learning_scope": ["docs"],
|
||||
},
|
||||
{
|
||||
"agent_id": "nemotron",
|
||||
"display_name": "NemoTron",
|
||||
"primary_specialty": "離線評估",
|
||||
"deployment_lane": "offline_evaluator",
|
||||
"allowed_autonomy": ["smoke"],
|
||||
"must_delegate_to": ["OpenClaw"],
|
||||
"blocked_actions": ["production_route"],
|
||||
"learning_scope": ["replay"],
|
||||
},
|
||||
],
|
||||
"domains": [
|
||||
{
|
||||
"domain_id": "hosts",
|
||||
"display_name": "主機",
|
||||
"description": "測試主機",
|
||||
}
|
||||
],
|
||||
"deployment_targets": [
|
||||
{
|
||||
"target_id": "host_110",
|
||||
"domain_id": "hosts",
|
||||
"display_name": "110",
|
||||
"target_type": "host",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["monitor"],
|
||||
"telegram_policy": "failure_only",
|
||||
"learning_inputs": ["metrics"],
|
||||
"communication_channels": ["Prometheus"],
|
||||
"approval_gate": "read_only_allowed",
|
||||
"evidence_refs": ["infra/ansible/inventory/hosts.yml"],
|
||||
"next_action": "觀察。",
|
||||
}
|
||||
],
|
||||
"collaboration_contract": {
|
||||
"message_bus": "Redis Streams",
|
||||
"audit_trail": "AgentSession",
|
||||
"handoff_rules": ["OpenClaw 仲裁"],
|
||||
"frontend_redaction": {
|
||||
"operator_conversation_display_allowed": False,
|
||||
"agent_private_reasoning_display_allowed": False,
|
||||
"display_policy": "只顯示摘要。",
|
||||
},
|
||||
},
|
||||
"learning_contract": {
|
||||
"event_sources": ["incident"],
|
||||
"feedback_loops": ["trust"],
|
||||
"growth_metrics": ["precision"],
|
||||
"retention_policy": "redacted evidence only",
|
||||
},
|
||||
"telegram_contract": {
|
||||
"primary_gateway": "telegram_gateway.py",
|
||||
"bot_roles": ["OpenClaw"],
|
||||
"notification_classes": ["failure"],
|
||||
"redaction_policy": "redacted",
|
||||
"e2e_validation": "ADR-035",
|
||||
},
|
||||
"rollups": {
|
||||
"total_targets": 1,
|
||||
"by_domain": {"hosts": 1},
|
||||
"by_primary_agent": {"openclaw": 1},
|
||||
"by_deployment_state": {"active_governed": 1},
|
||||
"by_telegram_policy": {"failure_only": 1},
|
||||
"blocked_target_ids": [],
|
||||
"approval_required_target_ids": [],
|
||||
},
|
||||
"approval_boundaries": {
|
||||
"sdk_installation_allowed": False,
|
||||
"paid_api_call_allowed": False,
|
||||
"shadow_or_canary_allowed": False,
|
||||
"production_routing_allowed": False,
|
||||
"destructive_operation_allowed": False,
|
||||
"secret_plaintext_allowed": False,
|
||||
"autonomous_host_mutation_allowed": False,
|
||||
"telegram_direct_send_allowed": False,
|
||||
},
|
||||
}
|
||||
31
apps/api/tests/test_ai_agent_deployment_layout_api.py
Normal file
31
apps/api/tests/test_ai_agent_deployment_layout_api.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from src.api.v1.agents import router
|
||||
|
||||
|
||||
def test_ai_agent_deployment_layout_endpoint_returns_committed_snapshot():
|
||||
app = FastAPI()
|
||||
app.include_router(router, prefix="/api/v1")
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.get("/api/v1/agents/agent-deployment-layout")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["schema_version"] == "ai_agent_deployment_layout_v1"
|
||||
assert data["program_status"]["overall_completion_percent"] == 45
|
||||
assert data["program_status"]["current_task_id"] == "P1-402"
|
||||
assert data["program_status"]["next_task_id"] == "P1-403"
|
||||
assert data["program_status"]["read_only_mode"] is True
|
||||
assert data["rollups"]["total_targets"] == 42
|
||||
assert data["rollups"]["by_domain"]["hosts"] == 6
|
||||
assert data["rollups"]["by_domain"]["websites"] == 5
|
||||
assert data["rollups"]["by_primary_agent"]["nemotron"] == 2
|
||||
assert data["approval_boundaries"]["telegram_direct_send_allowed"] is False
|
||||
assert data["approval_boundaries"]["autonomous_host_mutation_allowed"] is False
|
||||
assert data["collaboration_contract"]["frontend_redaction"]["operator_conversation_display_allowed"] is False
|
||||
assert any(target["target_id"] == "telegram_gateway" for target in data["deployment_targets"])
|
||||
assert any(target["target_id"] == "nemotron_replay_pipeline" for target in data["deployment_targets"])
|
||||
@@ -2965,6 +2965,72 @@
|
||||
"taskBoundaries": "任務邊界",
|
||||
"explicitApprovalTasks": "需明確批准"
|
||||
},
|
||||
"deploymentLayout": {
|
||||
"title": "OpenClaw / Hermes / NemoTron 佈建布局",
|
||||
"source": "{generated} · {current} → {next}",
|
||||
"targetsTitle": "優先佈建目標",
|
||||
"targetsShown": "顯示 {count}/{total}",
|
||||
"agentContractTitle": "Agent 專長分工",
|
||||
"telegramTitle": "Telegram Bot 告警合約",
|
||||
"telegramDetail": "統一入口 {gateway},通知類別 {classes} 種;Agent 不直接持有 token,也不直接發送。",
|
||||
"learningTitle": "主動學習與協作",
|
||||
"learningDetail": "事件來源 {sources}、回饋迴圈 {loops}、成長指標 {metrics};先落只讀證據,再走批准關卡。",
|
||||
"redactionLocked": "前端不顯示對話內容",
|
||||
"directSendBlocked": "Telegram 直送禁止",
|
||||
"frontendSafe": "只顯示狀態、證據與邊界",
|
||||
"metrics": {
|
||||
"targets": "佈建目標",
|
||||
"openclaw": "OpenClaw",
|
||||
"hermes": "Hermes",
|
||||
"nemotron": "NemoTron",
|
||||
"approval": "需批准",
|
||||
"blocked": "阻擋"
|
||||
},
|
||||
"labels": {
|
||||
"domain": "領域",
|
||||
"primary": "主責",
|
||||
"support": "協作",
|
||||
"telegram": "告警",
|
||||
"automation": "自動化",
|
||||
"evidence": "證據",
|
||||
"bus": "協作匯流"
|
||||
},
|
||||
"agents": {
|
||||
"openclaw": "OpenClaw",
|
||||
"hermes": "Hermes",
|
||||
"nemotron": "NemoTron"
|
||||
},
|
||||
"domains": {
|
||||
"hosts": "主機",
|
||||
"packages": "套件",
|
||||
"tools": "工具",
|
||||
"services": "服務",
|
||||
"projects": "專案",
|
||||
"websites": "網站前後台",
|
||||
"learning": "學習協作"
|
||||
},
|
||||
"deploymentStates": {
|
||||
"active_governed": "治理中",
|
||||
"read_only_layout": "只讀布局",
|
||||
"blocked_by_gate": "關卡阻擋",
|
||||
"planned": "規劃中",
|
||||
"candidate_only": "候選"
|
||||
},
|
||||
"automationLevels": {
|
||||
"observe_only": "只讀觀察",
|
||||
"prepare_only": "只準備提案",
|
||||
"dry_run_only": "僅乾跑",
|
||||
"hitl_execute_after_approval": "批准後 HITL 執行",
|
||||
"blocked": "阻擋"
|
||||
},
|
||||
"telegramPolicies": {
|
||||
"failure_only": "僅失敗",
|
||||
"action_required": "需處置",
|
||||
"approval_required": "需批准",
|
||||
"daily_summary_only": "僅日報",
|
||||
"no_direct_notify": "不直送"
|
||||
}
|
||||
},
|
||||
"overview": {
|
||||
"title": "決策指揮摘要",
|
||||
"mode": "只讀決策支援",
|
||||
|
||||
@@ -2965,6 +2965,72 @@
|
||||
"taskBoundaries": "任務邊界",
|
||||
"explicitApprovalTasks": "需明確批准"
|
||||
},
|
||||
"deploymentLayout": {
|
||||
"title": "OpenClaw / Hermes / NemoTron 佈建布局",
|
||||
"source": "{generated} · {current} → {next}",
|
||||
"targetsTitle": "優先佈建目標",
|
||||
"targetsShown": "顯示 {count}/{total}",
|
||||
"agentContractTitle": "Agent 專長分工",
|
||||
"telegramTitle": "Telegram Bot 告警合約",
|
||||
"telegramDetail": "統一入口 {gateway},通知類別 {classes} 種;Agent 不直接持有 token,也不直接發送。",
|
||||
"learningTitle": "主動學習與協作",
|
||||
"learningDetail": "事件來源 {sources}、回饋迴圈 {loops}、成長指標 {metrics};先落只讀證據,再走批准關卡。",
|
||||
"redactionLocked": "前端不顯示對話內容",
|
||||
"directSendBlocked": "Telegram 直送禁止",
|
||||
"frontendSafe": "只顯示狀態、證據與邊界",
|
||||
"metrics": {
|
||||
"targets": "佈建目標",
|
||||
"openclaw": "OpenClaw",
|
||||
"hermes": "Hermes",
|
||||
"nemotron": "NemoTron",
|
||||
"approval": "需批准",
|
||||
"blocked": "阻擋"
|
||||
},
|
||||
"labels": {
|
||||
"domain": "領域",
|
||||
"primary": "主責",
|
||||
"support": "協作",
|
||||
"telegram": "告警",
|
||||
"automation": "自動化",
|
||||
"evidence": "證據",
|
||||
"bus": "協作匯流"
|
||||
},
|
||||
"agents": {
|
||||
"openclaw": "OpenClaw",
|
||||
"hermes": "Hermes",
|
||||
"nemotron": "NemoTron"
|
||||
},
|
||||
"domains": {
|
||||
"hosts": "主機",
|
||||
"packages": "套件",
|
||||
"tools": "工具",
|
||||
"services": "服務",
|
||||
"projects": "專案",
|
||||
"websites": "網站前後台",
|
||||
"learning": "學習協作"
|
||||
},
|
||||
"deploymentStates": {
|
||||
"active_governed": "治理中",
|
||||
"read_only_layout": "只讀布局",
|
||||
"blocked_by_gate": "關卡阻擋",
|
||||
"planned": "規劃中",
|
||||
"candidate_only": "候選"
|
||||
},
|
||||
"automationLevels": {
|
||||
"observe_only": "只讀觀察",
|
||||
"prepare_only": "只準備提案",
|
||||
"dry_run_only": "僅乾跑",
|
||||
"hitl_execute_after_approval": "批准後 HITL 執行",
|
||||
"blocked": "阻擋"
|
||||
},
|
||||
"telegramPolicies": {
|
||||
"failure_only": "僅失敗",
|
||||
"action_required": "需處置",
|
||||
"approval_required": "需批准",
|
||||
"daily_summary_only": "僅日報",
|
||||
"no_direct_notify": "不直送"
|
||||
}
|
||||
},
|
||||
"overview": {
|
||||
"title": "決策指揮摘要",
|
||||
"mode": "只讀決策支援",
|
||||
|
||||
@@ -35,6 +35,7 @@ import { GlassCard } from '@/components/ui/glass-card'
|
||||
import { StatusOrb } from '@/components/ui/status-orb'
|
||||
import {
|
||||
apiClient,
|
||||
type AiAgentDeploymentLayoutSnapshot,
|
||||
type AiProviderRouteMatrixSnapshot,
|
||||
type AiAgentAutomationBacklogSnapshot,
|
||||
type AiAgentAutomationInventorySnapshot,
|
||||
@@ -311,6 +312,7 @@ export function AutomationInventoryTab() {
|
||||
const [giteaHealth, setGiteaHealth] = useState<GiteaWorkflowRunnerHealthSnapshot | null>(null)
|
||||
const [observabilityMatrix, setObservabilityMatrix] = useState<ObservabilityContractMatrixSnapshot | null>(null)
|
||||
const [providerRouteMatrix, setProviderRouteMatrix] = useState<AiProviderRouteMatrixSnapshot | null>(null)
|
||||
const [deploymentLayout, setDeploymentLayout] = useState<AiAgentDeploymentLayoutSnapshot | null>(null)
|
||||
const [serviceHealthGapMatrix, setServiceHealthGapMatrix] = useState<ServiceHealthGapMatrixSnapshot | null>(null)
|
||||
const [serviceHealthNotificationPolicy, setServiceHealthNotificationPolicy] = useState<ServiceHealthFailureNotificationPolicySnapshot | null>(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
@@ -329,6 +331,7 @@ export function AutomationInventoryTab() {
|
||||
apiClient.getGiteaWorkflowRunnerHealth(),
|
||||
apiClient.getObservabilityContractMatrix(),
|
||||
apiClient.getAiProviderRouteMatrix(),
|
||||
apiClient.getAiAgentDeploymentLayout(),
|
||||
apiClient.getServiceHealthGapMatrix(),
|
||||
apiClient.getServiceHealthFailureNotificationPolicy(),
|
||||
] as const
|
||||
@@ -346,6 +349,7 @@ export function AutomationInventoryTab() {
|
||||
giteaHealthResult,
|
||||
observabilityMatrixResult,
|
||||
providerRouteMatrixResult,
|
||||
deploymentLayoutResult,
|
||||
serviceHealthGapMatrixResult,
|
||||
serviceHealthNotificationPolicyResult,
|
||||
] = results
|
||||
@@ -360,6 +364,7 @@ export function AutomationInventoryTab() {
|
||||
setGiteaHealth(giteaHealthResult.status === 'fulfilled' ? giteaHealthResult.value : null)
|
||||
setObservabilityMatrix(observabilityMatrixResult.status === 'fulfilled' ? observabilityMatrixResult.value : null)
|
||||
setProviderRouteMatrix(providerRouteMatrixResult.status === 'fulfilled' ? providerRouteMatrixResult.value : null)
|
||||
setDeploymentLayout(deploymentLayoutResult.status === 'fulfilled' ? deploymentLayoutResult.value : null)
|
||||
setServiceHealthGapMatrix(serviceHealthGapMatrixResult.status === 'fulfilled' ? serviceHealthGapMatrixResult.value : null)
|
||||
setServiceHealthNotificationPolicy(serviceHealthNotificationPolicyResult.status === 'fulfilled' ? serviceHealthNotificationPolicyResult.value : null)
|
||||
setError([
|
||||
@@ -372,6 +377,7 @@ export function AutomationInventoryTab() {
|
||||
giteaHealthResult,
|
||||
observabilityMatrixResult,
|
||||
providerRouteMatrixResult,
|
||||
deploymentLayoutResult,
|
||||
serviceHealthGapMatrixResult,
|
||||
serviceHealthNotificationPolicyResult,
|
||||
].some(result => result.status === 'rejected'))
|
||||
@@ -409,6 +415,35 @@ export function AutomationInventoryTab() {
|
||||
.filter(group => group.items.length > 0)
|
||||
}, [backlog])
|
||||
|
||||
const visibleDeploymentTargets = useMemo(() => {
|
||||
if (!deploymentLayout) return []
|
||||
const statePriority = {
|
||||
blocked_by_gate: 0,
|
||||
active_governed: 1,
|
||||
read_only_layout: 2,
|
||||
planned: 3,
|
||||
candidate_only: 4,
|
||||
} as Record<string, number>
|
||||
const telegramPriority = {
|
||||
approval_required: 0,
|
||||
action_required: 1,
|
||||
failure_only: 2,
|
||||
daily_summary_only: 3,
|
||||
no_direct_notify: 4,
|
||||
} as Record<string, number>
|
||||
return [...deploymentLayout.deployment_targets]
|
||||
.sort((a, b) => {
|
||||
const stateLeft = statePriority[a.deployment_state] ?? 5
|
||||
const stateRight = statePriority[b.deployment_state] ?? 5
|
||||
if (stateLeft !== stateRight) return stateLeft - stateRight
|
||||
const telegramLeft = telegramPriority[a.telegram_policy] ?? 5
|
||||
const telegramRight = telegramPriority[b.telegram_policy] ?? 5
|
||||
if (telegramLeft !== telegramRight) return telegramLeft - telegramRight
|
||||
return a.target_id.localeCompare(b.target_id)
|
||||
})
|
||||
.slice(0, 12)
|
||||
}, [deploymentLayout])
|
||||
|
||||
const visibleReadinessRows = useMemo(() => {
|
||||
if (!backupReadiness) return []
|
||||
const priority = { blocked: 0, action_required: 1, deferred: 2, ready: 3 } as Record<string, number>
|
||||
@@ -552,7 +587,7 @@ export function AutomationInventoryTab() {
|
||||
)
|
||||
}
|
||||
|
||||
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
|
||||
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
|
||||
return (
|
||||
<div style={{ padding: 20 }}>
|
||||
<GlassCard variant="subtle" padding="lg">
|
||||
@@ -619,6 +654,12 @@ export function AutomationInventoryTab() {
|
||||
+ providerRouteMatrix.rollups.shadow_or_canary_allowed_count
|
||||
+ providerRouteMatrix.rollups.runtime_route_change_allowed_count
|
||||
)
|
||||
const deploymentLayoutTargets = deploymentLayout.rollups.total_targets
|
||||
const deploymentLayoutOpenClawTargets = deploymentLayout.rollups.by_primary_agent.openclaw ?? 0
|
||||
const deploymentLayoutHermesTargets = deploymentLayout.rollups.by_primary_agent.hermes ?? 0
|
||||
const deploymentLayoutNemotronTargets = deploymentLayout.rollups.by_primary_agent.nemotron ?? 0
|
||||
const deploymentLayoutBlockedTargets = deploymentLayout.rollups.blocked_target_ids.length
|
||||
const deploymentLayoutApprovalTargets = deploymentLayout.rollups.approval_required_target_ids.length
|
||||
const serviceHealthActions = serviceHealthGapMatrix.rollups.target_ids_requiring_action.length
|
||||
const serviceHealthStaleGaps = serviceHealthGapMatrix.rollups.stale_endpoint_ids.length
|
||||
const serviceHealthOperatorReviews = serviceHealthGapMatrix.rollups.health_gap_ids.length
|
||||
@@ -771,6 +812,14 @@ export function AutomationInventoryTab() {
|
||||
}
|
||||
}
|
||||
|
||||
const deploymentLayoutValueLabel = (group: string, value: string) => {
|
||||
try {
|
||||
return t(`deploymentLayout.${group}.${value}` as never)
|
||||
} catch {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
const serviceHealthValueLabel = (value: string) => {
|
||||
try {
|
||||
return t(`serviceHealth.values.${value}` as never)
|
||||
@@ -942,6 +991,124 @@ export function AutomationInventoryTab() {
|
||||
<MetricCard label={t('metrics.explicitApprovalTasks')} value={explicitApprovalTaskCount} tone={explicitApprovalTaskCount > 0 ? 'warn' : 'ok'} icon={<ShieldCheck size={16} />} />
|
||||
</div>
|
||||
|
||||
<GlassCard variant="subtle" padding="md">
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 13, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0 }}>
|
||||
<Route size={14} style={{ color: '#d97757' }} />
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 700, color: '#141413' }}>
|
||||
{t('deploymentLayout.title')}
|
||||
</span>
|
||||
</div>
|
||||
<Chip
|
||||
value={t('deploymentLayout.source', {
|
||||
generated: formatDateTime(deploymentLayout.generated_at),
|
||||
current: deploymentLayout.program_status.current_task_id,
|
||||
next: deploymentLayout.program_status.next_task_id,
|
||||
})}
|
||||
muted
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(6, minmax(0, 1fr))', gap: 12 }} className="automation-inventory-deployment-layout-kpi-grid">
|
||||
<MetricCard label={t('deploymentLayout.metrics.targets')} value={deploymentLayoutTargets} icon={<Boxes size={16} />} />
|
||||
<MetricCard label={t('deploymentLayout.metrics.openclaw')} value={deploymentLayoutOpenClawTargets} icon={<ShieldCheck size={16} />} />
|
||||
<MetricCard label={t('deploymentLayout.metrics.hermes')} value={deploymentLayoutHermesTargets} icon={<FileText size={16} />} />
|
||||
<MetricCard label={t('deploymentLayout.metrics.nemotron')} value={deploymentLayoutNemotronTargets} tone="warn" icon={<Target size={16} />} />
|
||||
<MetricCard label={t('deploymentLayout.metrics.approval')} value={deploymentLayoutApprovalTargets} tone={deploymentLayoutApprovalTargets > 0 ? 'warn' : 'ok'} icon={<Lock size={16} />} />
|
||||
<MetricCard label={t('deploymentLayout.metrics.blocked')} value={deploymentLayoutBlockedTargets} tone={deploymentLayoutBlockedTargets > 0 ? 'danger' : 'ok'} icon={<AlertTriangle size={16} />} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1.25fr) minmax(0, 0.75fr)', gap: 12 }} className="automation-inventory-deployment-layout-grid">
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 700, color: '#141413' }}>
|
||||
{t('deploymentLayout.targetsTitle')}
|
||||
</span>
|
||||
<Chip value={t('deploymentLayout.targetsShown', { count: visibleDeploymentTargets.length, total: deploymentLayoutTargets })} muted />
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 10 }} className="automation-inventory-deployment-layout-target-grid">
|
||||
{visibleDeploymentTargets.map(target => (
|
||||
<div key={target.target_id} style={{ padding: 11, border: '0.5px solid #e0ddd4', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, minWidth: 0 }}>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 11, fontWeight: 700, color: '#141413' }}>
|
||||
{target.target_id}
|
||||
</span>
|
||||
<Chip value={deploymentLayoutValueLabel('deploymentStates', target.deployment_state)} muted={target.deployment_state === 'active_governed'} />
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, minWidth: 0 }}>
|
||||
<Chip value={`${t('deploymentLayout.labels.domain')}: ${deploymentLayoutValueLabel('domains', target.domain_id)}`} muted />
|
||||
<Chip value={`${t('deploymentLayout.labels.primary')}: ${deploymentLayoutValueLabel('agents', target.primary_agent)}`} />
|
||||
<Chip value={`${t('deploymentLayout.labels.telegram')}: ${deploymentLayoutValueLabel('telegramPolicies', target.telegram_policy)}`} muted={target.telegram_policy !== 'approval_required'} />
|
||||
<Chip value={`${t('deploymentLayout.labels.automation')}: ${deploymentLayoutValueLabel('automationLevels', target.automation_level)}`} muted={target.automation_level === 'observe_only'} />
|
||||
</div>
|
||||
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
|
||||
{target.next_action}
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, minWidth: 0 }}>
|
||||
{target.supporting_agents.length > 0 ? (
|
||||
<Chip value={`${t('deploymentLayout.labels.support')}: ${target.supporting_agents.map(agent => deploymentLayoutValueLabel('agents', agent)).join(' / ')}`} muted />
|
||||
) : null}
|
||||
<Chip value={`${t('deploymentLayout.labels.evidence')}: ${target.evidence_refs.length}`} muted />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
|
||||
<div style={{ padding: 12, border: '0.5px solid #e0ddd4', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 9, minWidth: 0 }}>
|
||||
<SmallLabel>{t('deploymentLayout.agentContractTitle')}</SmallLabel>
|
||||
{deploymentLayout.agent_contracts.map(contract => (
|
||||
<div key={contract.agent_id} style={{ display: 'flex', flexDirection: 'column', gap: 5, paddingBottom: 7, borderBottom: '0.5px solid #eee9dd' }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 700, color: '#141413' }}>
|
||||
{deploymentLayoutValueLabel('agents', contract.agent_id)}
|
||||
</span>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45 }}>
|
||||
{contract.primary_specialty}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
{contract.allowed_autonomy.slice(0, 2).map(item => (
|
||||
<Chip key={`${contract.agent_id}-${item}`} value={item} muted />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 12, border: '0.5px solid #e0ddd4', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
||||
<SmallLabel>{t('deploymentLayout.telegramTitle')}</SmallLabel>
|
||||
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
|
||||
{t('deploymentLayout.telegramDetail', {
|
||||
gateway: deploymentLayout.telegram_contract.primary_gateway,
|
||||
classes: deploymentLayout.telegram_contract.notification_classes.length,
|
||||
})}
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t('deploymentLayout.redactionLocked')} />
|
||||
<Chip value={t('deploymentLayout.directSendBlocked')} muted />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 12, border: '0.5px solid #e0ddd4', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
||||
<SmallLabel>{t('deploymentLayout.learningTitle')}</SmallLabel>
|
||||
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
|
||||
{t('deploymentLayout.learningDetail', {
|
||||
sources: deploymentLayout.learning_contract.event_sources.length,
|
||||
loops: deploymentLayout.learning_contract.feedback_loops.length,
|
||||
metrics: deploymentLayout.learning_contract.growth_metrics.length,
|
||||
})}
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={`${t('deploymentLayout.labels.bus')}: ${deploymentLayout.collaboration_contract.message_bus}`} muted />
|
||||
<Chip value={t('deploymentLayout.frontendSafe')} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
<GlassCard variant="subtle" padding="md">
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 13, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
||||
@@ -2389,6 +2556,9 @@ export function AutomationInventoryTab() {
|
||||
.automation-inventory-provider-map-grid,
|
||||
.automation-inventory-provider-grid,
|
||||
.automation-inventory-provider-route-grid,
|
||||
.automation-inventory-deployment-layout-kpi-grid,
|
||||
.automation-inventory-deployment-layout-grid,
|
||||
.automation-inventory-deployment-layout-target-grid,
|
||||
.automation-inventory-service-health-kpi-grid,
|
||||
.automation-inventory-service-health-map-grid,
|
||||
.automation-inventory-service-health-evidence-grid,
|
||||
|
||||
@@ -262,6 +262,11 @@ export const apiClient = {
|
||||
return handleResponse<AiAgentAutomationBacklogSnapshot>(res)
|
||||
},
|
||||
|
||||
async getAiAgentDeploymentLayout() {
|
||||
const res = await fetch(`${API_BASE_URL}/agents/agent-deployment-layout`)
|
||||
return handleResponse<AiAgentDeploymentLayoutSnapshot>(res)
|
||||
},
|
||||
|
||||
async getRuntimeSurfaceInventory() {
|
||||
const res = await fetch(`${API_BASE_URL}/agents/runtime-surface-inventory`)
|
||||
return handleResponse<RuntimeSurfaceInventorySnapshot>(res)
|
||||
@@ -819,6 +824,109 @@ export interface AiAgentAutomationBacklogSnapshot {
|
||||
>
|
||||
}
|
||||
|
||||
export interface AiAgentDeploymentLayoutSnapshot {
|
||||
schema_version: 'ai_agent_deployment_layout_v1'
|
||||
generated_at: string
|
||||
program_status: {
|
||||
overall_completion_percent: number
|
||||
current_priority: 'P0' | 'P1' | 'P2' | 'P3'
|
||||
current_task_id: string
|
||||
next_task_id: string
|
||||
read_only_mode: true
|
||||
deployment_authority: 'layout_only_no_runtime_deploy'
|
||||
}
|
||||
agent_contracts: Array<{
|
||||
agent_id: string
|
||||
display_name: string
|
||||
primary_specialty: string
|
||||
deployment_lane: string
|
||||
allowed_autonomy: string[]
|
||||
must_delegate_to: string[]
|
||||
blocked_actions: string[]
|
||||
learning_scope: string[]
|
||||
}>
|
||||
domains: Array<{
|
||||
domain_id: string
|
||||
display_name: string
|
||||
description: string
|
||||
}>
|
||||
deployment_targets: Array<{
|
||||
target_id: string
|
||||
domain_id: string
|
||||
display_name: string
|
||||
target_type: string
|
||||
primary_agent: string
|
||||
supporting_agents: string[]
|
||||
deployment_state:
|
||||
| 'active_governed'
|
||||
| 'read_only_layout'
|
||||
| 'blocked_by_gate'
|
||||
| 'planned'
|
||||
| 'candidate_only'
|
||||
automation_level:
|
||||
| 'observe_only'
|
||||
| 'prepare_only'
|
||||
| 'dry_run_only'
|
||||
| 'hitl_execute_after_approval'
|
||||
| 'blocked'
|
||||
capabilities: string[]
|
||||
telegram_policy:
|
||||
| 'failure_only'
|
||||
| 'action_required'
|
||||
| 'approval_required'
|
||||
| 'daily_summary_only'
|
||||
| 'no_direct_notify'
|
||||
learning_inputs: string[]
|
||||
communication_channels: string[]
|
||||
approval_gate: string
|
||||
evidence_refs: string[]
|
||||
next_action: string
|
||||
}>
|
||||
collaboration_contract: {
|
||||
message_bus: string
|
||||
audit_trail: string
|
||||
handoff_rules: string[]
|
||||
frontend_redaction: {
|
||||
operator_conversation_display_allowed: false
|
||||
agent_private_reasoning_display_allowed: false
|
||||
display_policy: string
|
||||
}
|
||||
}
|
||||
learning_contract: {
|
||||
event_sources: string[]
|
||||
feedback_loops: string[]
|
||||
growth_metrics: string[]
|
||||
retention_policy: string
|
||||
}
|
||||
telegram_contract: {
|
||||
primary_gateway: string
|
||||
bot_roles: string[]
|
||||
notification_classes: string[]
|
||||
redaction_policy: string
|
||||
e2e_validation: string
|
||||
}
|
||||
rollups: {
|
||||
total_targets: number
|
||||
by_domain: Record<string, number>
|
||||
by_primary_agent: Record<string, number>
|
||||
by_deployment_state: Record<string, number>
|
||||
by_telegram_policy: Record<string, number>
|
||||
blocked_target_ids: string[]
|
||||
approval_required_target_ids: string[]
|
||||
}
|
||||
approval_boundaries: Record<
|
||||
| 'sdk_installation_allowed'
|
||||
| 'paid_api_call_allowed'
|
||||
| 'shadow_or_canary_allowed'
|
||||
| 'production_routing_allowed'
|
||||
| 'destructive_operation_allowed'
|
||||
| 'secret_plaintext_allowed'
|
||||
| 'autonomous_host_mutation_allowed'
|
||||
| 'telegram_direct_send_allowed',
|
||||
false
|
||||
>
|
||||
}
|
||||
|
||||
export interface RuntimeSurfaceInventorySnapshot {
|
||||
schema_version: 'runtime_surface_inventory_v1'
|
||||
generated_at: string
|
||||
|
||||
@@ -1,3 +1,27 @@
|
||||
## 2026-06-11|OpenClaw / Hermes / NemoTron 佈建布局第一波
|
||||
|
||||
**背景**:統帥要求將 OpenClaw、Hermes、NemoTron 依各自專長安排到所有主機、套件、工具、服務、專案、網站前後台,並納入主動學習、互相溝通、持續成長與 Telegram Bot 告警鏈路。本波先建立可驗證的只讀佈建布局,避免把尚未批准的 runtime deploy、SDK/API、Telegram 發送或主機操作誤當已授權。
|
||||
|
||||
**完成內容:**
|
||||
- 新增 `docs/schemas/ai_agent_deployment_layout_v1.schema.json`,定義三 Agent 佈建布局、target、Telegram policy、learning contract、collaboration contract 與 approval boundaries。
|
||||
- 新增 `docs/evaluations/ai_agent_deployment_layout_2026-06-11.json`,覆蓋 42 個 target:6 台主機、3 組套件、8 個工具、8 個服務、8 個專案、5 個網站前後台、4 個學習/協作面。
|
||||
- 新增 `apps/api/src/services/ai_agent_deployment_layout.py`,只讀載入最新 committed layout,並驗證 `production_routing_allowed`、`telegram_direct_send_allowed`、`autonomous_host_mutation_allowed` 等旗標必須維持 false。
|
||||
- 新增 `GET /api/v1/agents/agent-deployment-layout`,只讀回傳佈建布局;端點不部署 Agent、不呼叫外部模型、不送 Telegram、不碰 DB/Redis、不讀 Secret payload。
|
||||
- 新增 `docs/ai/AI_AGENT_DEPLOYMENT_LAYOUT_2026-06-11.md`,記錄 OpenClaw / Hermes / NemoTron 分工、Telegram 策略、主動學習與優先順序。
|
||||
- 更新 `docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md`,新增 P1-401 完成狀態與 P1-402 / P1-403 / P2-401 / P3-401 下一步。
|
||||
- 更新 `apps/web/src/lib/api-client.ts`,加入 `getAiAgentDeploymentLayout()` 與 `AiAgentDeploymentLayoutSnapshot` 型別,供治理後台後續接 UI 使用。
|
||||
- 更新 `apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx` 與 i18n,將三 Agent 佈建布局接入治理頁自動化盤點,只顯示狀態、證據、Agent 主責、Telegram policy 與批准邊界,不顯示工作對話內容。
|
||||
- 新增 `apps/api/tests/test_ai_agent_deployment_layout.py` 與 `apps/api/tests/test_ai_agent_deployment_layout_api.py`。
|
||||
|
||||
**完成度與邊界:**
|
||||
- 三 Agent 佈建布局合約:`100%`。
|
||||
- 三 Agent 佈建布局整體:`45%`,因目前已完成 schema / snapshot / API / 測試 / 報告 / 治理頁 UI,尚未做 runtime deploy、Telegram E2E 發送或 AgentSession worker。
|
||||
- NemoTron 仍維持離線評估 / smoke / replay 候選,不得直接進 shadow/canary/production route。
|
||||
- 所有 Telegram 通知必須走 Gateway / ADR-035;本波不直接送 Telegram、不讀 token、不新增 Bot secret。
|
||||
- 120 host 仍維持 blocked,不安排自動修復。
|
||||
- 前端只能顯示任務狀態、證據摘要、批准邊界與產物連結,不得顯示操作對話原文或 Agent 私有推理。
|
||||
- 本地驗證:JSON parse、API pytest、ruff、web typecheck 通過;in-app Browser 對本機 URL 被安全 policy 阻擋,未取得畫面截圖。
|
||||
|
||||
## 2026-06-11|IwoooS 即時資安危害優先序與 Wave 0 修補
|
||||
|
||||
**背景**:使用者調整 IwoooS 推進方向:不再把「完全不影響現有服務」放在所有工作之前,而是優先處理有即時性資訊安全危害的部分;處理過程仍需主動同步其他專案並避免未協調的服務中斷。本階段先確認全域資安範圍,並處理 source-control 層級可立即收斂的 P0。
|
||||
|
||||
@@ -11,10 +11,13 @@
|
||||
| Agent 市場治理 | 72% | 進行中 | `agent_market_governance_snapshot_v1`、API、UI 分頁、每週觀察流程 |
|
||||
| Nemotron 實際整合應用 | 30% | 完整回放前仍被關卡擋下 | `blocked_needs_evidence`,下一關是 `refresh_source_evidence_then_5_record_smoke_only` |
|
||||
| 工具 / 服務 / 套件 AI 自動化 | 92% | P0 已完成;P1 服務 / runtime / 監控 / provider / service health / 備份 / DR / 套件與供應鏈只讀基線已完成;P1-007 失敗限定通知合約與前端 redaction 合約已完成;下一主線是 P2-004 依賴 / 供應鏈漂移監控 | 狀態分類、盤點 schema、權限矩陣、靜態盤點種子、只讀 API、UI 骨架、驗證、自動化待辦 schema / 快照 / API / 分組 UI、Backup / DR 目標盤點、準備度矩陣、備份通知政策、Backup / DR 證據 UI、復原演練批准包模板、異地 / escrow 準備度狀態、任務批准邊界、確定性進度彙總、Python 套件 / 供應鏈只讀基線、JS pnpm/npm 只讀基線、Docker build surface 只讀基線、CVE / license / drift 嚴重度政策、定期依賴漂移與外部資料來源檢查設計、依賴升級批准包模板、runtime_surface_inventory_v1 schema / snapshot / API / UI、gitea_workflow_runner_health_v1 schema / snapshot / API / UI、observability_contract_matrix_v1 schema / snapshot / API / UI、ai_provider_route_matrix_v1 schema / snapshot / API / UI、service_health_gap_matrix_v1 schema / snapshot / API / UI、service health evidence cards UI、service_health_failure_notification_policy_v1 schema / snapshot / API / UI 已完成 |
|
||||
| OpenClaw / Hermes / NemoTron 佈建布局 | 45% | P1-401 / P1-402 已完成;仍是只讀 layout 與治理頁顯示,不是 runtime deploy | `ai_agent_deployment_layout_v1` schema、`ai_agent_deployment_layout_2026-06-11.json`、`GET /api/v1/agents/agent-deployment-layout`、治理頁自動化盤點 UI、`AI_AGENT_DEPLOYMENT_LAYOUT_2026-06-11.md` |
|
||||
| 本工作清單與分析報告 | 100% | 已完成 | 本 MD 文件 |
|
||||
|
||||
AI Agent 自動化工作包目前完成度:**92%**。本工作清單文件本身完成度:**100%**。
|
||||
|
||||
三 Agent 佈建布局目前完成度:**45%**。第一波已完成只讀 schema / snapshot / API / 測試 / 報告,第二波已接入治理頁自動化盤點 UI;正式 runtime 佈署、Telegram E2E 發送與 AgentSession 工作流仍需逐項 gate。
|
||||
|
||||
完成度計算模型:
|
||||
|
||||
```text
|
||||
@@ -54,6 +57,19 @@ AI Agent 自動化工作包目前完成度:**92%**。本工作清單文件本
|
||||
| Claude Agent SDK 候選 | DevOps / 程式修復專家 | 離線修復評分、patch plan 批判 | SDK/API 使用、未經 OpenClaw/HITL 的執行 |
|
||||
| CrewAI / ADK / Microsoft 候選 | 次級或平台候選 | 觀察 / 回放準備度、能力評分表 | 生產執行 |
|
||||
|
||||
### 3.1 OpenClaw / Hermes / NemoTron 佈建布局(P1-401)
|
||||
|
||||
| 項目 | 狀態 |
|
||||
|---|---|
|
||||
| 佈建布局 schema | 已完成:`docs/schemas/ai_agent_deployment_layout_v1.schema.json` |
|
||||
| 佈建布局 snapshot | 已完成:`docs/evaluations/ai_agent_deployment_layout_2026-06-11.json` |
|
||||
| 只讀 API | 已完成:`GET /api/v1/agents/agent-deployment-layout` |
|
||||
| 細化報告 | 已完成:`docs/ai/AI_AGENT_DEPLOYMENT_LAYOUT_2026-06-11.md` |
|
||||
| 前端治理 UI | 已完成:P1-402,治理頁自動化盤點 tab 已顯示佈建布局、主責 Agent、Telegram policy、批准/阻擋狀態 |
|
||||
| Telegram 三 Agent lane E2E | 待辦:P1-403,必須沿用 Gateway / ADR-035,不允許 Agent 直接發送 |
|
||||
| AgentSession / Redis Streams runtime loop | 待辦:P2-401,需 migration / worker gate |
|
||||
| NemoTron 3 Ultra smoke | 待辦:P3-401,需 source refresh + cost/data approval |
|
||||
|
||||
## 4. 工作流總覽
|
||||
|
||||
| ID | 工作流 | 目標 | 目前狀態 | 目標狀態 |
|
||||
|
||||
116
docs/ai/AI_AGENT_DEPLOYMENT_LAYOUT_2026-06-11.md
Normal file
116
docs/ai/AI_AGENT_DEPLOYMENT_LAYOUT_2026-06-11.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# OpenClaw / Hermes / NemoTron 佈建布局與協作報告
|
||||
|
||||
> 日期:2026-06-11(台北時間)
|
||||
> 狀態:只讀布局與治理頁接線完成,runtime 佈署尚未授權。
|
||||
> 權威資料:`docs/evaluations/ai_agent_deployment_layout_2026-06-11.json`
|
||||
> Schema:`docs/schemas/ai_agent_deployment_layout_v1.schema.json`
|
||||
> API:`GET /api/v1/agents/agent-deployment-layout`
|
||||
|
||||
## 1. 結論
|
||||
|
||||
目前已把 OpenClaw、Hermes、NemoTron 依各自專長安排到主機、套件、工具、服務、專案、網站前後台、學習協作與 Telegram 告警布局中。
|
||||
|
||||
本波完成的是「可驗證佈建布局」,不是直接把 Agent 遠端安裝到所有主機;因此不會碰 Secret、不送 Telegram、不改主機、不裝 SDK、不呼叫付費 API、不進 shadow/canary、不改 production route。
|
||||
|
||||
## 2. 完成度
|
||||
|
||||
| 範圍 | 完成度 | 狀態 |
|
||||
|---|---:|---|
|
||||
| 三 Agent 佈建布局合約 | 100% | Schema、snapshot、loader、API、測試已建立 |
|
||||
| 佈建布局資料覆蓋 | 100% | 42 個 target 已納入 |
|
||||
| 治理頁只讀顯示 | 100% | 自動化盤點 tab 已接 API 與繁中顯示 |
|
||||
| Runtime 實際部署 | 0% | 需要逐項 gate / approval / deploy |
|
||||
| Telegram Gateway 整合布局 | 70% | 既有 Gateway / ADR-035 可承接;本波不直接送訊息 |
|
||||
| 主動學習與協作布局 | 45% | 已定義 AgentSession / Redis Streams / KM / replay 回饋;runtime loop 需後續落地 |
|
||||
|
||||
## 3. Agent 分工
|
||||
|
||||
| Agent | 專長 | 主要佈建 lane | 可主動做 | 必須交給誰 |
|
||||
|---|---|---|---|---|
|
||||
| OpenClaw | 生產仲裁、HITL、執行風險、Telegram action-required | production decision core | 只讀診斷、風險分級、批准包審查、批准後執行仲裁 | Hermes 彙整治理;NemoTron 做離線模型評估 |
|
||||
| Hermes | 治理、知識、文件、套件/供應鏈、降噪、跨專案盤點 | governance / knowledge / reporting | 盤點、報告、runbook、依賴漂移、降噪提案、批准包草稿 | OpenClaw 仲裁生產與 Telegram;NemoTron 評估模型能力 |
|
||||
| NemoTron | 離線專家、模型比較、工具呼叫、NIM / NVIDIA replay | offline evaluator | sanitized smoke、replay 評分、輸出合約檢查、模型能力矩陣 | OpenClaw 仲裁 shadow/canary/production;Hermes 彙整來源與報告 |
|
||||
|
||||
## 4. 覆蓋範圍
|
||||
|
||||
| Domain | Target 數 | 主要 owner |
|
||||
|---|---:|---|
|
||||
| 主機 | 6 | OpenClaw |
|
||||
| 套件與建置 | 3 | Hermes |
|
||||
| 工具 | 8 | Hermes / OpenClaw |
|
||||
| 服務 | 8 | OpenClaw / Hermes |
|
||||
| 專案 | 8 | Hermes / OpenClaw |
|
||||
| 網站前後台 | 5 | Hermes / OpenClaw |
|
||||
| 學習與協作 | 4 | OpenClaw / Hermes / NemoTron |
|
||||
|
||||
合計:42 個 target。
|
||||
|
||||
## 5. 主機佈建策略
|
||||
|
||||
| 主機 | 角色 | 主 Agent | 狀態 | Telegram |
|
||||
|---|---|---|---|---|
|
||||
| 110 | DevOps / runner / monitoring | OpenClaw | active_governed | action_required |
|
||||
| 188 | AI / Web / DB / Redis / SigNoz | OpenClaw | active_governed | action_required |
|
||||
| 111 | Ollama fallback | OpenClaw | read_only_layout | failure_only |
|
||||
| 120 | K3s blocked recovery | OpenClaw | blocked_by_gate | action_required |
|
||||
| 121 | K3s peer | OpenClaw | active_governed | failure_only |
|
||||
| 112 | Kali / security evidence | Hermes | read_only_layout | no_direct_notify |
|
||||
|
||||
120 仍維持 blocked,不安排自動修復;必須等 console / SSH / K3s evidence 回來。
|
||||
|
||||
## 6. Telegram 策略
|
||||
|
||||
所有 Agent 都不得直接持有 token 或直接送訊息;統一經 `apps/api/src/services/telegram_gateway.py` 與 ADR-035 的部署後 E2E 驗證鏈路。
|
||||
|
||||
通知等級:
|
||||
|
||||
| 類型 | 策略 |
|
||||
|---|---|
|
||||
| critical failure | 立即告警 |
|
||||
| operator action required | 立即告警 |
|
||||
| approval required | Telegram approval card |
|
||||
| success / healthy | 壓低或每日摘要 |
|
||||
| watch-only no-op | 靜默 |
|
||||
|
||||
訊息不得包含 Secret、token、cookie、private key、原始 payload、操作對話原文或 Agent 私有推理。
|
||||
|
||||
## 7. 主動學習與互相溝通
|
||||
|
||||
協作路徑:
|
||||
|
||||
1. Prometheus / Sentry / SigNoz / backup / runtime snapshot 產生事件。
|
||||
2. Hermes 先彙整只讀證據與 runbook / dependency / market context。
|
||||
3. OpenClaw 仲裁風險、HITL、Telegram action-required 與是否能進 dry-run。
|
||||
4. NemoTron 只處理 sanitized smoke / replay / model comparison。
|
||||
5. 結果回寫 AgentSession、Timeline、KM、Playbook trust 與 market scorecard。
|
||||
|
||||
學習來源:
|
||||
|
||||
- incident timeline
|
||||
- approval outcome
|
||||
- alert operation log
|
||||
- service health snapshot
|
||||
- backup / DR evidence
|
||||
- dependency drift snapshot
|
||||
- agent market watch
|
||||
- NemoTron smoke / replay result
|
||||
|
||||
## 8. 優先順序
|
||||
|
||||
| 優先級 | 任務 | 狀態 | 下一步 |
|
||||
|---|---|---|---|
|
||||
| P1-401 | 建立三 Agent 佈建布局 schema / snapshot / API | 完成 | 進入 Telegram / 協作 runtime gate |
|
||||
| P1-402 | 治理後台顯示佈建布局 | 完成 | 已顯示 target、owner、Telegram policy、批准/阻擋狀態 |
|
||||
| P1-403 | Telegram Gateway 對三 Agent lane 做 E2E smoke 包 | 待辦 | 不直接發送,先做批准包 |
|
||||
| P2-401 | AgentSession / Redis Streams 協作資料面落地 | 待辦 | 需要 migration / worker gate |
|
||||
| P2-402 | Playbook trust / KM / operator feedback loop 補強 | 待辦 | 先做只讀報表 |
|
||||
| P3-401 | NemoTron 3 Ultra source refresh + 5-record smoke | 待辦 | 需要 cost/data approval 後才能跑 |
|
||||
|
||||
## 9. 紅線
|
||||
|
||||
- 不把布局當成 runtime 授權。
|
||||
- 不把 AwoooP work item 當成生產批准。
|
||||
- 不把 IwoooS UI 可見當成安全授權。
|
||||
- 不讓 NemoTron 在 smoke/replay gate 前進 shadow/canary。
|
||||
- 不讓 Hermes 直接發 Telegram 或修改生產。
|
||||
- 不讓任何 Agent 顯示操作對話原文或私有推理到前端。
|
||||
976
docs/evaluations/ai_agent_deployment_layout_2026-06-11.json
Normal file
976
docs/evaluations/ai_agent_deployment_layout_2026-06-11.json
Normal file
@@ -0,0 +1,976 @@
|
||||
{
|
||||
"schema_version": "ai_agent_deployment_layout_v1",
|
||||
"generated_at": "2026-06-11T18:20:00+08:00",
|
||||
"program_status": {
|
||||
"overall_completion_percent": 45,
|
||||
"current_priority": "P1",
|
||||
"current_task_id": "P1-402",
|
||||
"next_task_id": "P1-403",
|
||||
"read_only_mode": true,
|
||||
"deployment_authority": "layout_only_no_runtime_deploy"
|
||||
},
|
||||
"agent_contracts": [
|
||||
{
|
||||
"agent_id": "openclaw",
|
||||
"display_name": "OpenClaw",
|
||||
"primary_specialty": "生產仲裁、風險判斷、HITL 關卡與執行前後驗證",
|
||||
"deployment_lane": "production_decision_core",
|
||||
"allowed_autonomy": [
|
||||
"只讀診斷",
|
||||
"風險分級",
|
||||
"批准包審查",
|
||||
"Telegram action-required 分流",
|
||||
"批准後的 dry-run / 執行仲裁"
|
||||
],
|
||||
"must_delegate_to": [
|
||||
"Hermes 負責治理、文件、降噪與盤點彙整",
|
||||
"NemoTron 負責離線模型能力比較與 replay 評分"
|
||||
],
|
||||
"blocked_actions": [
|
||||
"未批准的生產寫入",
|
||||
"未批准的 destructive operation",
|
||||
"未批准的 provider route 切換",
|
||||
"未批准的 Telegram 直接發送",
|
||||
"未通過 replacement gate 前降級或取代自身生產角色"
|
||||
],
|
||||
"learning_scope": [
|
||||
"incident lifecycle",
|
||||
"approval outcome",
|
||||
"post-execution verification",
|
||||
"playbook trust score",
|
||||
"alert grouping quality"
|
||||
]
|
||||
},
|
||||
{
|
||||
"agent_id": "hermes",
|
||||
"display_name": "Hermes",
|
||||
"primary_specialty": "治理、知識管理、文件、套件/供應鏈、降噪與跨專案盤點",
|
||||
"deployment_lane": "governance_knowledge_and_reporting",
|
||||
"allowed_autonomy": [
|
||||
"只讀盤點",
|
||||
"Runbook / KM 草稿",
|
||||
"市場與依賴漂移摘要",
|
||||
"告警降噪提案",
|
||||
"批准包起草"
|
||||
],
|
||||
"must_delegate_to": [
|
||||
"OpenClaw 仲裁任何生產、Telegram、host mutation 或 rollback",
|
||||
"NemoTron 評估模型/工具能力與 replay 結果"
|
||||
],
|
||||
"blocked_actions": [
|
||||
"直接改生產環境",
|
||||
"直接發送 Telegram 通知",
|
||||
"直接修改 Secret",
|
||||
"自行升級套件或 SDK",
|
||||
"自行切換 AI provider"
|
||||
],
|
||||
"learning_scope": [
|
||||
"runbook freshness",
|
||||
"docs drift",
|
||||
"dependency drift",
|
||||
"service health evidence gap",
|
||||
"operator review feedback"
|
||||
]
|
||||
},
|
||||
{
|
||||
"agent_id": "nemotron",
|
||||
"display_name": "NemoTron / Nemotron",
|
||||
"primary_specialty": "離線專家評估、模型工具能力比較、NIM/NVIDIA replay 與長任務 Agent 能力驗證",
|
||||
"deployment_lane": "offline_evaluator_and_specialist_candidate",
|
||||
"allowed_autonomy": [
|
||||
"sanitized request pack 分析",
|
||||
"5-record smoke 評分",
|
||||
"50-record replay 結果比較",
|
||||
"工具呼叫輸出合約檢查",
|
||||
"候選模型能力矩陣更新"
|
||||
],
|
||||
"must_delegate_to": [
|
||||
"OpenClaw 仲裁生產風險與是否可進 shadow/canary",
|
||||
"Hermes 彙整市場來源、文件與 operator 報告"
|
||||
],
|
||||
"blocked_actions": [
|
||||
"直接讀取 production secret",
|
||||
"未批准的 paid API / NIM 呼叫",
|
||||
"未批准的 SDK 安裝",
|
||||
"未通過 smoke gate 前進 full replay",
|
||||
"自行進 shadow/canary 或生產路由"
|
||||
],
|
||||
"learning_scope": [
|
||||
"smoke gate failures",
|
||||
"output contract completeness",
|
||||
"latency budget",
|
||||
"tool calling reliability",
|
||||
"OpenClaw same-run baseline delta"
|
||||
]
|
||||
}
|
||||
],
|
||||
"domains": [
|
||||
{
|
||||
"domain_id": "hosts",
|
||||
"display_name": "主機",
|
||||
"description": "110 / 111 / 112 / 120 / 121 / 188 的只讀監控、診斷、備份與批准後修復佈局。"
|
||||
},
|
||||
{
|
||||
"domain_id": "packages",
|
||||
"display_name": "套件與建置",
|
||||
"description": "Python、pnpm/npm、Docker base image、CVE、license、digest 與 drift。"
|
||||
},
|
||||
{
|
||||
"domain_id": "tools",
|
||||
"display_name": "工具",
|
||||
"description": "Gitea、Harbor、Prometheus、Alertmanager、SigNoz、Sentry、Open-WebUI、Telegram、Ansible。"
|
||||
},
|
||||
{
|
||||
"domain_id": "services",
|
||||
"display_name": "服務",
|
||||
"description": "API、Web、AwoooP、IwoooS、PostgreSQL、Redis、K8s workload 與內部控制面。"
|
||||
},
|
||||
{
|
||||
"domain_id": "projects",
|
||||
"display_name": "專案",
|
||||
"description": "AWOOOI 及已納入治理視野的外部/相鄰專案。"
|
||||
},
|
||||
{
|
||||
"domain_id": "websites",
|
||||
"display_name": "網站前後台",
|
||||
"description": "公開站、治理後台、告警後台、AwoooP 後台、IwoooS 後台。"
|
||||
},
|
||||
{
|
||||
"domain_id": "learning",
|
||||
"display_name": "學習與協作",
|
||||
"description": "AgentSession、KM、Playbook trust、market watch、replay harness。"
|
||||
}
|
||||
],
|
||||
"deployment_targets": [
|
||||
{
|
||||
"target_id": "host_110",
|
||||
"domain_id": "hosts",
|
||||
"display_name": "110 DevOps / Gitea runner / monitoring host",
|
||||
"target_type": "host",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "prepare_only",
|
||||
"capabilities": ["host health diagnosis", "runner health review", "backup freshness review", "approval package"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["Gitea workflow result", "runner evidence", "backup status", "Alertmanager route"],
|
||||
"communication_channels": ["AwoooP approval", "Telegram failure/action-required", "Prometheus metrics"],
|
||||
"approval_gate": "host mutation requires human approval",
|
||||
"evidence_refs": ["infra/ansible/inventory/hosts.yml", "docs/evaluations/gitea_workflow_runner_health_2026-06-05.json"],
|
||||
"next_action": "把 runner / backup / monitoring 狀態納入 Agent 協作節點,但只允許準備修復提案。"
|
||||
},
|
||||
{
|
||||
"target_id": "host_188",
|
||||
"domain_id": "hosts",
|
||||
"display_name": "188 AI / Web / PostgreSQL / Redis / SigNoz host",
|
||||
"target_type": "host",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes", "nemotron"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "prepare_only",
|
||||
"capabilities": ["AI provider health review", "database/cache health review", "observability review", "NemoTron candidate evidence"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["AI route matrix", "DB backup status", "SigNoz/ClickHouse evidence", "NemoTron smoke result"],
|
||||
"communication_channels": ["AwoooP approval", "Telegram failure/action-required", "Prometheus metrics"],
|
||||
"approval_gate": "host mutation, service restart, provider route change require explicit approval",
|
||||
"evidence_refs": ["infra/ansible/inventory/hosts.yml", "docs/evaluations/ai_provider_route_matrix_2026-06-05.json"],
|
||||
"next_action": "建立 OpenClaw 主仲裁、Hermes 彙整、NemoTron 離線評估的 host-188 協作節點。"
|
||||
},
|
||||
{
|
||||
"target_id": "host_111",
|
||||
"domain_id": "hosts",
|
||||
"display_name": "111 Ollama fallback host",
|
||||
"target_type": "host",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "read_only_layout",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["fallback health observation", "route readiness review"],
|
||||
"telegram_policy": "failure_only",
|
||||
"learning_inputs": ["Ollama health", "provider failover evidence"],
|
||||
"communication_channels": ["Prometheus metrics", "Telegram failure-only"],
|
||||
"approval_gate": "SSH / service operation requires approval",
|
||||
"evidence_refs": ["infra/ansible/inventory/hosts.yml", "docs/runbooks/RUNBOOK-OLLAMA-FAILOVER.md"],
|
||||
"next_action": "保持只讀觀察,避免因 fallback 健康誤判而切換 provider。"
|
||||
},
|
||||
{
|
||||
"target_id": "host_120",
|
||||
"domain_id": "hosts",
|
||||
"display_name": "120 K3s master / blocked recovery host",
|
||||
"target_type": "host",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "blocked_by_gate",
|
||||
"automation_level": "blocked",
|
||||
"capabilities": ["blocked-state tracking", "recovery checklist", "backup config capture blocker"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["cold-start scorecard", "backup config capture", "host reachability"],
|
||||
"communication_channels": ["Telegram action-required", "LOGBOOK", "cold-start runbook"],
|
||||
"approval_gate": "console/SSH recovery evidence required before any automation",
|
||||
"evidence_refs": ["docs/runbooks/BACKUP-STATUS.md", "docs/runbooks/FULL-STACK-COLD-START-SOP.md"],
|
||||
"next_action": "維持 blocked,不安排自動修復,等待 console / SSH 復原證據。"
|
||||
},
|
||||
{
|
||||
"target_id": "host_121",
|
||||
"domain_id": "hosts",
|
||||
"display_name": "121 K3s peer host",
|
||||
"target_type": "host",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["K3s readiness observation", "failover context", "backup/cold-start evidence"],
|
||||
"telegram_policy": "failure_only",
|
||||
"learning_inputs": ["K3s node readiness", "host connectivity", "cold-start scorecard"],
|
||||
"communication_channels": ["Prometheus metrics", "Telegram failure-only"],
|
||||
"approval_gate": "K3s mutation requires maintenance window approval",
|
||||
"evidence_refs": ["infra/ansible/inventory/hosts.yml", "docs/runbooks/K3S-OPTIMIZATION-RUNBOOK.md"],
|
||||
"next_action": "將 121 視為 K3s readiness 證據節點,不做未批准操作。"
|
||||
},
|
||||
{
|
||||
"target_id": "host_112",
|
||||
"domain_id": "hosts",
|
||||
"display_name": "112 Kali / security evidence host",
|
||||
"target_type": "host",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "read_only_layout",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["security evidence catalog", "owner response package", "read-only posture projection"],
|
||||
"telegram_policy": "no_direct_notify",
|
||||
"learning_inputs": ["IwoooS posture projection", "owner response evidence"],
|
||||
"communication_channels": ["IwoooS read-only handoff", "operator review"],
|
||||
"approval_gate": "active scan / host update / credentialed scan require independent approval",
|
||||
"evidence_refs": ["docs/security/iwooos-posture-projection.snapshot.json", "infra/ansible/inventory/hosts.yml"],
|
||||
"next_action": "維持只讀安全證據,不啟用 active scan。"
|
||||
},
|
||||
{
|
||||
"target_id": "pkg_python_api",
|
||||
"domain_id": "packages",
|
||||
"display_name": "API Python dependencies",
|
||||
"target_type": "package_set",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["dependency inventory", "CVE/license drift review", "upgrade approval package"],
|
||||
"telegram_policy": "daily_summary_only",
|
||||
"learning_inputs": ["package inventory", "CVE policy", "dependency drift plan"],
|
||||
"communication_channels": ["governance UI", "daily summary only"],
|
||||
"approval_gate": "dependency upgrade requires approval package",
|
||||
"evidence_refs": ["docs/evaluations/package_supply_chain_inventory_2026-06-04.json"],
|
||||
"next_action": "Hermes 週期性彙整漂移,OpenClaw 只仲裁高風險升級。"
|
||||
},
|
||||
{
|
||||
"target_id": "pkg_web_pnpm",
|
||||
"domain_id": "packages",
|
||||
"display_name": "Web pnpm/npm dependencies",
|
||||
"target_type": "package_set",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["package inventory", "lockfile drift review", "upgrade proposal"],
|
||||
"telegram_policy": "daily_summary_only",
|
||||
"learning_inputs": ["javascript package inventory", "dependency drift plan"],
|
||||
"communication_channels": ["governance UI", "daily summary only"],
|
||||
"approval_gate": "package upgrade / install requires approval",
|
||||
"evidence_refs": ["docs/evaluations/javascript_package_inventory_2026-06-04.json"],
|
||||
"next_action": "只產生升級批准包,不自動 npm/pnpm install。"
|
||||
},
|
||||
{
|
||||
"target_id": "docker_build_surface",
|
||||
"domain_id": "packages",
|
||||
"display_name": "Docker base image and build surface",
|
||||
"target_type": "container_image",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "prepare_only",
|
||||
"capabilities": ["digest drift review", "base image risk review", "build-surface proposal"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["docker build surface inventory", "CVE policy"],
|
||||
"communication_channels": ["governance UI", "Telegram action-required for critical drift"],
|
||||
"approval_gate": "image digest/base image change requires review and deploy gate",
|
||||
"evidence_refs": ["docs/evaluations/docker_build_surface_inventory_2026-06-04.json"],
|
||||
"next_action": "把 critical image drift 送 OpenClaw 仲裁,其他由 Hermes 月報。"
|
||||
},
|
||||
{
|
||||
"target_id": "gitea_actions",
|
||||
"domain_id": "tools",
|
||||
"display_name": "Gitea Actions and host runner",
|
||||
"target_type": "workflow_tool",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["workflow health matrix", "runner attestation", "notification hygiene"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["workflow results", "runner evidence", "CI failure classes"],
|
||||
"communication_channels": ["Gitea Actions summary", "Telegram actionable/failure only"],
|
||||
"approval_gate": "workflow modification requires review",
|
||||
"evidence_refs": ["docs/evaluations/gitea_workflow_runner_health_2026-06-05.json", ".gitea/workflows/"],
|
||||
"next_action": "Hermes 彙整 runner / workflow gaps;OpenClaw 只仲裁部署或 workflow 修改。"
|
||||
},
|
||||
{
|
||||
"target_id": "harbor_registry",
|
||||
"domain_id": "tools",
|
||||
"display_name": "Harbor registry",
|
||||
"target_type": "registry",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "read_only_layout",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["backup freshness", "image inventory", "registry health summary"],
|
||||
"telegram_policy": "failure_only",
|
||||
"learning_inputs": ["backup target inventory", "registry backup evidence"],
|
||||
"communication_channels": ["backup policy", "Telegram failure-only"],
|
||||
"approval_gate": "registry cleanup / retention change requires approval",
|
||||
"evidence_refs": ["scripts/backup/backup-harbor.sh", "docs/evaluations/backup_dr_target_inventory_2026-06-04.json"],
|
||||
"next_action": "只監控 backup / freshness,不自動刪 image。"
|
||||
},
|
||||
{
|
||||
"target_id": "prometheus_alertmanager",
|
||||
"domain_id": "tools",
|
||||
"display_name": "Prometheus / Alertmanager",
|
||||
"target_type": "observability",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "prepare_only",
|
||||
"capabilities": ["alert contract review", "noise reduction proposal", "E2E chain evidence"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["alert rules", "alert chain metrics", "notification outcome"],
|
||||
"communication_channels": ["Alertmanager webhook", "Telegram action-required"],
|
||||
"approval_gate": "alert rule deploy / silence requires approval",
|
||||
"evidence_refs": ["docs/evaluations/observability_contract_matrix_2026-06-05.json", "docs/adr/ADR-035-telegram-alert-chain-enforcement.md"],
|
||||
"next_action": "保持告警必到,成功訊息降噪,規則部署另走 deploy-alerts gate。"
|
||||
},
|
||||
{
|
||||
"target_id": "signoz_clickhouse",
|
||||
"domain_id": "tools",
|
||||
"display_name": "SigNoz / ClickHouse",
|
||||
"target_type": "observability",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["trace evidence", "log evidence", "storage health review"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["SigNoz alert", "ClickHouse health", "trace/log evidence"],
|
||||
"communication_channels": ["governance UI", "Telegram action-required"],
|
||||
"approval_gate": "query-heavy or retention change requires approval",
|
||||
"evidence_refs": ["docs/evaluations/observability_contract_matrix_2026-06-05.json", "ops/signoz"],
|
||||
"next_action": "Hermes 做證據摘要,OpenClaw 仲裁重大 storage / retention 風險。"
|
||||
},
|
||||
{
|
||||
"target_id": "sentry",
|
||||
"domain_id": "tools",
|
||||
"display_name": "Sentry",
|
||||
"target_type": "observability",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["issue summary", "frontend/backend error drift", "release evidence"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["Sentry issue class", "release marker", "frontend/backend route"],
|
||||
"communication_channels": ["governance UI", "Telegram action-required"],
|
||||
"approval_gate": "Sentry DSN / project setting change requires approval",
|
||||
"evidence_refs": ["apps/web/src/instrumentation.ts", "scripts/backup/backup-sentry.sh"],
|
||||
"next_action": "只讀錯誤分類,不讀 secret,不直接建立/修改 Sentry 設定。"
|
||||
},
|
||||
{
|
||||
"target_id": "open_webui",
|
||||
"domain_id": "tools",
|
||||
"display_name": "Open-WebUI / AI workspace",
|
||||
"target_type": "ai_tool",
|
||||
"primary_agent": "nemotron",
|
||||
"supporting_agents": ["hermes", "openclaw"],
|
||||
"deployment_state": "candidate_only",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["model evaluation evidence", "AI artifact inventory", "offline specialist review"],
|
||||
"telegram_policy": "no_direct_notify",
|
||||
"learning_inputs": ["AI artifact backup", "model evaluation", "operator review"],
|
||||
"communication_channels": ["offline report", "governance UI"],
|
||||
"approval_gate": "external model call / NIM route requires cost and data-boundary approval",
|
||||
"evidence_refs": ["scripts/backup/backup-open-webui.sh", "docs/evaluations/agent_nemotron_contract_tuned_smoke_matrix_2026-06-02.json"],
|
||||
"next_action": "NemoTron 只做離線評估,不接 production route。"
|
||||
},
|
||||
{
|
||||
"target_id": "telegram_gateway",
|
||||
"domain_id": "tools",
|
||||
"display_name": "Telegram Gateway / Bot alert chain",
|
||||
"target_type": "notification_gateway",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "hitl_execute_after_approval",
|
||||
"capabilities": ["failure-only routing", "approval card", "dedup", "E2E validation"],
|
||||
"telegram_policy": "approval_required",
|
||||
"learning_inputs": ["notification outcome", "dedup result", "operator button action"],
|
||||
"communication_channels": ["Telegram Bot", "AwoooP approval", "alert operation log"],
|
||||
"approval_gate": "direct send / bot token change / chat target change requires approval and E2E smoke",
|
||||
"evidence_refs": ["apps/api/src/services/telegram_gateway.py", "docs/adr/ADR-035-telegram-alert-chain-enforcement.md"],
|
||||
"next_action": "把三 Agent 的通知都收斂到 Gateway,不讓 Agent 直接持有 token 或直接發送。"
|
||||
},
|
||||
{
|
||||
"target_id": "ansible_control",
|
||||
"domain_id": "tools",
|
||||
"display_name": "Ansible host control plane",
|
||||
"target_type": "host_iac",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "read_only_layout",
|
||||
"automation_level": "hitl_execute_after_approval",
|
||||
"capabilities": ["check-mode proposal", "host-state drift", "rollback plan"],
|
||||
"telegram_policy": "approval_required",
|
||||
"learning_inputs": ["Ansible check-mode", "host textfile exporter", "operator approval outcome"],
|
||||
"communication_channels": ["AwoooP approval", "Telegram approval-required"],
|
||||
"approval_gate": "any ansible apply requires independent human approval",
|
||||
"evidence_refs": ["docs/runbooks/ANSIBLE-OPERATING-MODEL.md", "infra/ansible/inventory/hosts.yml"],
|
||||
"next_action": "先建立 check-mode 證據;apply 仍必須人工批准。"
|
||||
},
|
||||
{
|
||||
"target_id": "awoooi_api",
|
||||
"domain_id": "services",
|
||||
"display_name": "AWOOOI API backend",
|
||||
"target_type": "api",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes", "nemotron"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "prepare_only",
|
||||
"capabilities": ["incident decision", "MCP context", "agent API snapshots", "post-execution verification"],
|
||||
"telegram_policy": "failure_only",
|
||||
"learning_inputs": ["incident", "timeline event", "approval record", "agent snapshot"],
|
||||
"communication_channels": ["API", "Redis stream", "Telegram failure-only"],
|
||||
"approval_gate": "runtime deploy / DB migration / provider route change requires CD gate",
|
||||
"evidence_refs": ["apps/api/src/api/v1/agents.py", "docs/evaluations/runtime_surface_inventory_2026-06-05.json"],
|
||||
"next_action": "把新佈建布局暴露為只讀 API,不新增執行端點。"
|
||||
},
|
||||
{
|
||||
"target_id": "awoooi_web",
|
||||
"domain_id": "services",
|
||||
"display_name": "AWOOOI public web frontend",
|
||||
"target_type": "web",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["frontend evidence display", "i18n review", "route health summary"],
|
||||
"telegram_policy": "failure_only",
|
||||
"learning_inputs": ["browser smoke", "Sentry issue", "i18n validation"],
|
||||
"communication_channels": ["governance UI", "Sentry", "Telegram failure-only"],
|
||||
"approval_gate": "frontend deploy requires CD validation and production smoke",
|
||||
"evidence_refs": ["apps/web/src/app/[locale]/governance/page.tsx", "docs/evaluations/runtime_surface_inventory_2026-06-05.json"],
|
||||
"next_action": "Hermes 維護 UI/文案與證據卡;OpenClaw 仲裁發布風險。"
|
||||
},
|
||||
{
|
||||
"target_id": "governance_backoffice",
|
||||
"domain_id": "services",
|
||||
"display_name": "Governance backoffice",
|
||||
"target_type": "backoffice",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["automation inventory", "agent market", "service health", "deployment layout display"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["snapshot freshness", "operator review", "blocked gate count"],
|
||||
"communication_channels": ["governance UI", "AwoooP work item"],
|
||||
"approval_gate": "UI display is not runtime authorization",
|
||||
"evidence_refs": ["apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx"],
|
||||
"next_action": "將本 layout 先接進只讀 API,再接治理 UI。"
|
||||
},
|
||||
{
|
||||
"target_id": "awooop_control_plane",
|
||||
"domain_id": "services",
|
||||
"display_name": "AwoooP control plane",
|
||||
"target_type": "control_plane",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "hitl_execute_after_approval",
|
||||
"capabilities": ["work item", "approval", "truth chain", "run state"],
|
||||
"telegram_policy": "approval_required",
|
||||
"learning_inputs": ["approval decision", "run state", "operator timeline"],
|
||||
"communication_channels": ["AwoooP approvals", "Telegram approval card"],
|
||||
"approval_gate": "AwoooP work item is not security or production approval by itself",
|
||||
"evidence_refs": ["apps/web/src/app/[locale]/awooop/page.tsx", "docs/awooop/MASTER-WORKPLAN.md"],
|
||||
"next_action": "OpenClaw 只把 AwoooP 當批准/證據控制面,不讓候選 Agent 直接執行。"
|
||||
},
|
||||
{
|
||||
"target_id": "iwooos_security_surface",
|
||||
"domain_id": "services",
|
||||
"display_name": "IwoooS security surface",
|
||||
"target_type": "security_surface",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["read-only evidence", "owner response packet", "security posture"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["owner response gate", "redacted evidence refs", "scope handoff"],
|
||||
"communication_channels": ["IwoooS page", "operator review", "Telegram action-required only"],
|
||||
"approval_gate": "active runtime / scan / host update remains false until independent approval",
|
||||
"evidence_refs": ["apps/web/src/app/[locale]/iwooos/page.tsx", "docs/security/iwooos-posture-projection.snapshot.json"],
|
||||
"next_action": "Hermes 整理資安證據,OpenClaw 守住 active runtime gate。"
|
||||
},
|
||||
{
|
||||
"target_id": "postgresql_primary",
|
||||
"domain_id": "services",
|
||||
"display_name": "PostgreSQL primary data layer",
|
||||
"target_type": "database",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "prepare_only",
|
||||
"capabilities": ["connection health", "backup freshness", "migration risk", "slow query evidence"],
|
||||
"telegram_policy": "failure_only",
|
||||
"learning_inputs": ["DB alert", "backup status", "migration outcome"],
|
||||
"communication_channels": ["Prometheus", "backup status", "Telegram failure-only"],
|
||||
"approval_gate": "migration / restore / schema change requires approval and backup evidence",
|
||||
"evidence_refs": ["apps/api/migrations/", "docs/evaluations/backup_dr_readiness_matrix_2026-06-04.json"],
|
||||
"next_action": "OpenClaw 仲裁 DB 風險;Hermes 產出備份與 migration 證據摘要。"
|
||||
},
|
||||
{
|
||||
"target_id": "redis_cache",
|
||||
"domain_id": "services",
|
||||
"display_name": "Redis / Stream / cache layer",
|
||||
"target_type": "cache",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "prepare_only",
|
||||
"capabilities": ["stream backlog review", "cache health", "agent bus readiness"],
|
||||
"telegram_policy": "failure_only",
|
||||
"learning_inputs": ["Redis alert", "agent stream backlog", "approval outcome"],
|
||||
"communication_channels": ["Prometheus", "Agent stream", "Telegram failure-only"],
|
||||
"approval_gate": "flush / restart / data mutation requires approval",
|
||||
"evidence_refs": ["docs/evaluations/service_health_gap_matrix_2026-06-05.json", "docs/adr/ADR-082-multi-agent-collaboration.md"],
|
||||
"next_action": "用 Redis stream 作為 Agent 協作匯流,但不允許無批准清除資料。"
|
||||
},
|
||||
{
|
||||
"target_id": "k8s_workloads",
|
||||
"domain_id": "services",
|
||||
"display_name": "K8s workloads / manifests",
|
||||
"target_type": "k8s",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "dry_run_only",
|
||||
"capabilities": ["manifest mapping", "rollout evidence", "drift interpretation", "dry-run proposal"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["runtime surface inventory", "drift report", "post-execution verifier"],
|
||||
"communication_channels": ["AwoooP approval", "Telegram action-required", "Prometheus"],
|
||||
"approval_gate": "kubectl apply / rollout / scale / delete requires approval",
|
||||
"evidence_refs": ["k8s/awoooi-prod/", "docs/evaluations/runtime_surface_inventory_2026-06-05.json"],
|
||||
"next_action": "OpenClaw 做乾跑仲裁,Hermes 彙整 manifest 與 runbook。"
|
||||
},
|
||||
{
|
||||
"target_id": "project_awoooi",
|
||||
"domain_id": "projects",
|
||||
"display_name": "AWOOOI core project",
|
||||
"target_type": "project",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes", "nemotron"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "prepare_only",
|
||||
"capabilities": ["incident governance", "agent market governance", "runtime truth", "deployment evidence"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["LOGBOOK", "HARD_RULES", "market watch", "runtime smoke"],
|
||||
"communication_channels": ["Gitea", "AwoooP", "Telegram", "governance UI"],
|
||||
"approval_gate": "production deploy and provider changes require existing CD/HITL gates",
|
||||
"evidence_refs": ["docs/HARD_RULES.md", "docs/LOGBOOK.md"],
|
||||
"next_action": "把三 Agent 佈局做成 AWOOOI 的正式只讀控制面資料。"
|
||||
},
|
||||
{
|
||||
"target_id": "project_awooop",
|
||||
"domain_id": "projects",
|
||||
"display_name": "AwoooP operations project surface",
|
||||
"target_type": "project",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "hitl_execute_after_approval",
|
||||
"capabilities": ["work item", "approval queue", "run monitor", "contract governance"],
|
||||
"telegram_policy": "approval_required",
|
||||
"learning_inputs": ["work item status", "approval outcome", "truth chain"],
|
||||
"communication_channels": ["AwoooP UI", "Telegram approval card"],
|
||||
"approval_gate": "AwoooP approval is necessary but not sufficient for security or host mutation",
|
||||
"evidence_refs": ["docs/awooop/MASTER-WORKPLAN.md", "apps/web/src/app/[locale]/awooop/"],
|
||||
"next_action": "將 Agent 佈局轉為 AwoooP work item templates,但不自動簽核。"
|
||||
},
|
||||
{
|
||||
"target_id": "project_iwooos",
|
||||
"domain_id": "projects",
|
||||
"display_name": "IwoooS security governance",
|
||||
"target_type": "project",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["scope handoff", "owner response gate", "redacted evidence"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["IwoooS posture projection", "owner response state"],
|
||||
"communication_channels": ["IwoooS UI", "operator review"],
|
||||
"approval_gate": "UI-visible state must not be treated as runtime authorization",
|
||||
"evidence_refs": ["docs/security/iwooos-posture-projection.snapshot.json"],
|
||||
"next_action": "Hermes 維持只讀證據卡,OpenClaw 防止 runtime gate 被誤開。"
|
||||
},
|
||||
{
|
||||
"target_id": "project_vibework",
|
||||
"domain_id": "projects",
|
||||
"display_name": "VibeWork adjacent product",
|
||||
"target_type": "adjacent_project",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "read_only_layout",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["boundary inventory", "release evidence summary", "alert routing expectation"],
|
||||
"telegram_policy": "no_direct_notify",
|
||||
"learning_inputs": ["cross-project handoff", "runtime evidence if explicitly supplied"],
|
||||
"communication_channels": ["operator report only"],
|
||||
"approval_gate": "separate repo/runtime approval required",
|
||||
"evidence_refs": ["docs/security/vibework-iwooos-onboarding-handoff.snapshot.json"],
|
||||
"next_action": "只保留治理視野,不跨 repo 自動部署。"
|
||||
},
|
||||
{
|
||||
"target_id": "project_stockplatform",
|
||||
"domain_id": "projects",
|
||||
"display_name": "StockPlatform adjacent product",
|
||||
"target_type": "adjacent_project",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["nemotron", "openclaw"],
|
||||
"deployment_state": "read_only_layout",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["AI research governance", "dry-run review", "human-review boundary"],
|
||||
"telegram_policy": "no_direct_notify",
|
||||
"learning_inputs": ["research governance note", "operator-approved evidence"],
|
||||
"communication_channels": ["operator report only"],
|
||||
"approval_gate": "separate project approval required before any runtime work",
|
||||
"evidence_refs": ["docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md"],
|
||||
"next_action": "NemoTron 只可作研究乾跑,不作投資建議或生產推薦。"
|
||||
},
|
||||
{
|
||||
"target_id": "project_tsenyang",
|
||||
"domain_id": "projects",
|
||||
"display_name": "TSENYANG website adjacent project",
|
||||
"target_type": "adjacent_project",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "read_only_layout",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["SEO/launch evidence summary", "analytics boundary review"],
|
||||
"telegram_policy": "no_direct_notify",
|
||||
"learning_inputs": ["operator-approved launch evidence"],
|
||||
"communication_channels": ["operator report only"],
|
||||
"approval_gate": "separate repo/runtime approval required",
|
||||
"evidence_refs": ["docs/security/iwooos-posture-projection.snapshot.json"],
|
||||
"next_action": "只保留跨產品治理視角,不直接改網站。"
|
||||
},
|
||||
{
|
||||
"target_id": "project_bitan",
|
||||
"domain_id": "projects",
|
||||
"display_name": "Bitan Pharmacy adjacent project",
|
||||
"target_type": "adjacent_project",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "read_only_layout",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["production recovery evidence summary", "AI ops loop review"],
|
||||
"telegram_policy": "no_direct_notify",
|
||||
"learning_inputs": ["operator-approved recovery evidence"],
|
||||
"communication_channels": ["operator report only"],
|
||||
"approval_gate": "separate repo/runtime approval required",
|
||||
"evidence_refs": ["docs/security/iwooos-posture-projection.snapshot.json"],
|
||||
"next_action": "只列入相鄰產品治理,不跨專案部署。"
|
||||
},
|
||||
{
|
||||
"target_id": "project_agent_bounty",
|
||||
"domain_id": "projects",
|
||||
"display_name": "agent-bounty-protocol onboarding surface",
|
||||
"target_type": "adjacent_project",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "read_only_layout",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["read-only security onboarding", "owner gate", "external agent boundary"],
|
||||
"telegram_policy": "no_direct_notify",
|
||||
"learning_inputs": ["agent bounty onboarding handoff", "owner response status"],
|
||||
"communication_channels": ["IwoooS read-only handoff", "operator report"],
|
||||
"approval_gate": "no runtime, repo, scan, cron, payout or contract action without explicit approval",
|
||||
"evidence_refs": ["docs/security/agent-bounty-iwooos-onboarding-handoff.snapshot.json"],
|
||||
"next_action": "維持 IwoooS 只讀收件,不跨到 agent-bounty runtime。"
|
||||
},
|
||||
{
|
||||
"target_id": "public_frontend",
|
||||
"domain_id": "websites",
|
||||
"display_name": "Public frontend routes",
|
||||
"target_type": "website_frontend",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["browser smoke evidence", "i18n coverage", "route health"],
|
||||
"telegram_policy": "failure_only",
|
||||
"learning_inputs": ["browser smoke", "Sentry error", "route uptime"],
|
||||
"communication_channels": ["Sentry", "Prometheus", "Telegram failure-only"],
|
||||
"approval_gate": "frontend deploy requires build/typecheck/browser smoke",
|
||||
"evidence_refs": ["apps/web/src/app/[locale]/page.tsx"],
|
||||
"next_action": "Hermes 負責內容/顯示品質;OpenClaw 仲裁發布風險。"
|
||||
},
|
||||
{
|
||||
"target_id": "governance_ui",
|
||||
"domain_id": "websites",
|
||||
"display_name": "Governance UI backoffice",
|
||||
"target_type": "website_backoffice",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["agent market display", "automation inventory display", "deployment layout display"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["operator review", "snapshot freshness", "blocked gate count"],
|
||||
"communication_channels": ["governance UI", "AwoooP work item"],
|
||||
"approval_gate": "UI display does not authorize runtime action",
|
||||
"evidence_refs": ["apps/web/src/app/[locale]/governance/page.tsx"],
|
||||
"next_action": "新增只讀 layout 資料源後再接 UI 呈現。"
|
||||
},
|
||||
{
|
||||
"target_id": "alerts_backoffice",
|
||||
"domain_id": "websites",
|
||||
"display_name": "Alerts and operation-log backoffice",
|
||||
"target_type": "website_backoffice",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "prepare_only",
|
||||
"capabilities": ["incident triage", "alert operation log", "operator action request"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["alert operation log", "incident timeline", "notification outcome"],
|
||||
"communication_channels": ["alert-operation-logs UI", "Telegram action-required"],
|
||||
"approval_gate": "alert action execution requires approval",
|
||||
"evidence_refs": ["apps/web/src/app/[locale]/alerts/page.tsx", "apps/web/src/app/[locale]/alert-operation-logs/page.tsx"],
|
||||
"next_action": "OpenClaw 產生 action proposal;Hermes 彙整趨勢與降噪。"
|
||||
},
|
||||
{
|
||||
"target_id": "awooop_admin",
|
||||
"domain_id": "websites",
|
||||
"display_name": "AwoooP admin routes",
|
||||
"target_type": "website_backoffice",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "hitl_execute_after_approval",
|
||||
"capabilities": ["approval queue", "runs", "contracts", "tenants"],
|
||||
"telegram_policy": "approval_required",
|
||||
"learning_inputs": ["approval decision", "run evidence", "contract state"],
|
||||
"communication_channels": ["AwoooP UI", "Telegram approval card"],
|
||||
"approval_gate": "AwoooP UI action requires separate policy and human approval",
|
||||
"evidence_refs": ["apps/web/src/app/[locale]/awooop/"],
|
||||
"next_action": "將三 Agent 提案映射成 AwoooP work item,不讓候選 Agent 直接執行。"
|
||||
},
|
||||
{
|
||||
"target_id": "iwooos_admin",
|
||||
"domain_id": "websites",
|
||||
"display_name": "IwoooS read-only security routes",
|
||||
"target_type": "website_backoffice",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["security mirror", "scope card", "owner response gate"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["owner response", "security posture", "redacted refs"],
|
||||
"communication_channels": ["IwoooS UI", "operator review"],
|
||||
"approval_gate": "IwoooS visibility is not active runtime authorization",
|
||||
"evidence_refs": ["apps/web/src/app/[locale]/iwooos/page.tsx"],
|
||||
"next_action": "繼續維持低摩擦只讀資安治理。"
|
||||
},
|
||||
{
|
||||
"target_id": "agent_session_bus",
|
||||
"domain_id": "learning",
|
||||
"display_name": "AgentSession / Redis Streams collaboration bus",
|
||||
"target_type": "learning_bus",
|
||||
"primary_agent": "openclaw",
|
||||
"supporting_agents": ["hermes", "nemotron"],
|
||||
"deployment_state": "planned",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["agent handoff", "turn audit", "replayable collaboration"],
|
||||
"telegram_policy": "no_direct_notify",
|
||||
"learning_inputs": ["agent session turn", "critic challenge", "coordinator decision"],
|
||||
"communication_channels": ["Redis stream", "agent_sessions audit"],
|
||||
"approval_gate": "new runtime worker or schema migration requires approval",
|
||||
"evidence_refs": ["docs/adr/ADR-082-multi-agent-collaboration.md"],
|
||||
"next_action": "先補只讀 layout;下一波才評估是否需要 migration / worker。"
|
||||
},
|
||||
{
|
||||
"target_id": "km_playbook_learning",
|
||||
"domain_id": "learning",
|
||||
"display_name": "KM / Playbook trust learning loop",
|
||||
"target_type": "learning_loop",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw"],
|
||||
"deployment_state": "planned",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["runbook freshness", "playbook trust evidence", "negative reinforcement"],
|
||||
"telegram_policy": "daily_summary_only",
|
||||
"learning_inputs": ["execution result", "post verification", "operator review"],
|
||||
"communication_channels": ["KM", "LOGBOOK", "daily summary only"],
|
||||
"approval_gate": "playbook promotion requires review",
|
||||
"evidence_refs": ["docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md"],
|
||||
"next_action": "Hermes 整理學習素材,OpenClaw 仲裁是否可升為 approved playbook。"
|
||||
},
|
||||
{
|
||||
"target_id": "nemotron_replay_pipeline",
|
||||
"domain_id": "learning",
|
||||
"display_name": "NemoTron smoke / replay pipeline",
|
||||
"target_type": "model_replay",
|
||||
"primary_agent": "nemotron",
|
||||
"supporting_agents": ["openclaw", "hermes"],
|
||||
"deployment_state": "blocked_by_gate",
|
||||
"automation_level": "blocked",
|
||||
"capabilities": ["5-record smoke", "output contract review", "latency budget", "same-run baseline delta"],
|
||||
"telegram_policy": "approval_required",
|
||||
"learning_inputs": ["smoke gate", "external runner report", "OpenClaw baseline"],
|
||||
"communication_channels": ["offline report", "operator review", "Telegram approval-required after gate"],
|
||||
"approval_gate": "refresh source evidence, cost/data approval, then 5-record smoke only",
|
||||
"evidence_refs": ["docs/evaluations/agent_nemotron_contract_tuned_smoke_matrix_2026-06-02.json", "docs/runbooks/OPENCLAW-REPLACEMENT-EVALUATION.md"],
|
||||
"next_action": "新增 Nemotron 3 Ultra source evidence 後,先重跑 5-record smoke。"
|
||||
},
|
||||
{
|
||||
"target_id": "agent_market_watch",
|
||||
"domain_id": "learning",
|
||||
"display_name": "AI Agent market watch",
|
||||
"target_type": "market_watch",
|
||||
"primary_agent": "hermes",
|
||||
"supporting_agents": ["openclaw", "nemotron"],
|
||||
"deployment_state": "active_governed",
|
||||
"automation_level": "observe_only",
|
||||
"capabilities": ["primary-source scan", "integration review", "discovery intake", "candidate scoring"],
|
||||
"telegram_policy": "action_required",
|
||||
"learning_inputs": ["official docs", "release metadata", "scorecard", "operator review"],
|
||||
"communication_channels": ["Gitea Actions", "governance UI", "Telegram actionable only"],
|
||||
"approval_gate": "market watch cannot approve SDK/API/replay/shadow/canary/production",
|
||||
"evidence_refs": [".gitea/workflows/agent-market-watch.yaml", "docs/evaluations/agent_market_governance_snapshot_2026-06-04.json"],
|
||||
"next_action": "把 Nemotron 3 Ultra 納入下一次 source refresh 和 scorecard review。"
|
||||
}
|
||||
],
|
||||
"collaboration_contract": {
|
||||
"message_bus": "以 Redis Streams / AgentSession / timeline event 作為可回放協作總線;本快照只描述布局,不啟動新 worker。",
|
||||
"audit_trail": "所有 Agent 建議必須落到可查詢事件、批准包或 committed snapshot;不得只存在聊天視窗。",
|
||||
"handoff_rules": [
|
||||
"OpenClaw 收斂生產風險、HITL 與 Telegram action-required。",
|
||||
"Hermes 收斂治理、文件、盤點、降噪與跨專案報告。",
|
||||
"NemoTron 收斂 sanitized 離線評估、模型比較與 replay score。",
|
||||
"任何 Agent 發現風險升級時必須轉交 OpenClaw 仲裁。",
|
||||
"任何 Agent 發現市場/依賴漂移時必須轉交 Hermes 彙整。",
|
||||
"任何候選模型能力聲稱必須先經 NemoTron 或 replay harness 產出同題證據。"
|
||||
],
|
||||
"frontend_redaction": {
|
||||
"operator_conversation_display_allowed": false,
|
||||
"agent_private_reasoning_display_allowed": false,
|
||||
"display_policy": "前端只能顯示任務狀態、證據摘要、批准邊界與產物連結;不得顯示操作對話原文或 Agent 私有推理。"
|
||||
}
|
||||
},
|
||||
"learning_contract": {
|
||||
"event_sources": [
|
||||
"incident timeline",
|
||||
"approval outcome",
|
||||
"alert operation log",
|
||||
"service health snapshot",
|
||||
"backup / DR evidence",
|
||||
"dependency drift snapshot",
|
||||
"agent market watch",
|
||||
"NemoTron smoke / replay result"
|
||||
],
|
||||
"feedback_loops": [
|
||||
"成功/失敗/中性結果回寫 Playbook trust",
|
||||
"Critic / Reviewer 挑戰結果回寫 AgentSession",
|
||||
"Telegram 按鈕與 operator review 回寫 notification outcome",
|
||||
"Market watch source delta 進入 scorecard / replay gate",
|
||||
"NemoTron replay 失敗模式回寫 prompt / contract 改善清單"
|
||||
],
|
||||
"growth_metrics": [
|
||||
"playbook trust_score 有效更新數",
|
||||
"general fallback alert ratio",
|
||||
"agent handoff completion rate",
|
||||
"notification failure rate",
|
||||
"smoke gate pass rate",
|
||||
"operator-approved proposal precision"
|
||||
],
|
||||
"retention_policy": "學習資料只保留 redacted evidence refs、hash、分類與結果;Secret、token、原始對話與私有推理不得進前端或告警。"
|
||||
},
|
||||
"telegram_contract": {
|
||||
"primary_gateway": "apps/api/src/services/telegram_gateway.py",
|
||||
"bot_roles": [
|
||||
"OpenClaw Bot:生產告警、批准、HITL 與 action-required。",
|
||||
"Hermes Bot lane:治理摘要、週期性報告與降噪候選,但仍經 Gateway。",
|
||||
"NemoTron lane:只在 smoke/replay gate 需要 operator review 時產生摘要,不能直接發送。"
|
||||
],
|
||||
"notification_classes": [
|
||||
"critical failure: immediate",
|
||||
"operator action required: immediate",
|
||||
"approval required: approval card",
|
||||
"success / healthy: suppressed or daily summary",
|
||||
"watch-only no-op: quiet"
|
||||
],
|
||||
"redaction_policy": "不得在 Telegram 顯示 Secret、token、cookie、private key、原始 payload、操作對話原文或 Agent 私有推理;只顯示 evidence ref、狀態、影響範圍與下一步。",
|
||||
"e2e_validation": "沿用 ADR-035:部署前檢查 Secret、部署時注入 K8s Secret、部署後做 E2E 告警鏈路驗證;本布局不直接送測試通知。"
|
||||
},
|
||||
"rollups": {
|
||||
"total_targets": 42,
|
||||
"by_domain": {
|
||||
"hosts": 6,
|
||||
"packages": 3,
|
||||
"tools": 8,
|
||||
"services": 8,
|
||||
"projects": 8,
|
||||
"websites": 5,
|
||||
"learning": 4
|
||||
},
|
||||
"by_primary_agent": {
|
||||
"openclaw": 17,
|
||||
"hermes": 23,
|
||||
"nemotron": 2
|
||||
},
|
||||
"by_deployment_state": {
|
||||
"active_governed": 28,
|
||||
"read_only_layout": 9,
|
||||
"blocked_by_gate": 2,
|
||||
"planned": 2,
|
||||
"candidate_only": 1
|
||||
},
|
||||
"by_telegram_policy": {
|
||||
"failure_only": 8,
|
||||
"action_required": 17,
|
||||
"approval_required": 6,
|
||||
"daily_summary_only": 3,
|
||||
"no_direct_notify": 8
|
||||
},
|
||||
"blocked_target_ids": [
|
||||
"host_120",
|
||||
"nemotron_replay_pipeline"
|
||||
],
|
||||
"approval_required_target_ids": [
|
||||
"host_120",
|
||||
"telegram_gateway",
|
||||
"ansible_control",
|
||||
"awooop_control_plane",
|
||||
"project_awooop",
|
||||
"awooop_admin",
|
||||
"nemotron_replay_pipeline"
|
||||
]
|
||||
},
|
||||
"approval_boundaries": {
|
||||
"sdk_installation_allowed": false,
|
||||
"paid_api_call_allowed": false,
|
||||
"shadow_or_canary_allowed": false,
|
||||
"production_routing_allowed": false,
|
||||
"destructive_operation_allowed": false,
|
||||
"secret_plaintext_allowed": false,
|
||||
"autonomous_host_mutation_allowed": false,
|
||||
"telegram_direct_send_allowed": false
|
||||
}
|
||||
}
|
||||
343
docs/schemas/ai_agent_deployment_layout_v1.schema.json
Normal file
343
docs/schemas/ai_agent_deployment_layout_v1.schema.json
Normal file
@@ -0,0 +1,343 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "urn:awoooi:ai-agent-deployment-layout-v1",
|
||||
"title": "AWOOOI AI Agent 佈建布局快照 v1",
|
||||
"description": "OpenClaw、Hermes、NemoTron 在主機、套件、工具、服務、專案與網站前後台的只讀佈建布局合約。此 schema 不授權任何生產寫入、Telegram 發送、SDK 安裝、付費 API、shadow/canary 或生產路由切換。",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema_version",
|
||||
"generated_at",
|
||||
"program_status",
|
||||
"agent_contracts",
|
||||
"domains",
|
||||
"deployment_targets",
|
||||
"collaboration_contract",
|
||||
"learning_contract",
|
||||
"telegram_contract",
|
||||
"rollups",
|
||||
"approval_boundaries"
|
||||
],
|
||||
"properties": {
|
||||
"schema_version": {
|
||||
"type": "string",
|
||||
"const": "ai_agent_deployment_layout_v1"
|
||||
},
|
||||
"generated_at": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"program_status": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"overall_completion_percent",
|
||||
"current_priority",
|
||||
"current_task_id",
|
||||
"next_task_id",
|
||||
"read_only_mode",
|
||||
"deployment_authority"
|
||||
],
|
||||
"properties": {
|
||||
"overall_completion_percent": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
"current_priority": {
|
||||
"type": "string",
|
||||
"enum": ["P0", "P1", "P2", "P3"]
|
||||
},
|
||||
"current_task_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"next_task_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"read_only_mode": {
|
||||
"type": "boolean",
|
||||
"const": true
|
||||
},
|
||||
"deployment_authority": {
|
||||
"type": "string",
|
||||
"const": "layout_only_no_runtime_deploy"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"agent_contracts": {
|
||||
"type": "array",
|
||||
"minItems": 3,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"agent_id",
|
||||
"display_name",
|
||||
"primary_specialty",
|
||||
"deployment_lane",
|
||||
"allowed_autonomy",
|
||||
"must_delegate_to",
|
||||
"blocked_actions",
|
||||
"learning_scope"
|
||||
],
|
||||
"properties": {
|
||||
"agent_id": {"type": "string", "minLength": 1},
|
||||
"display_name": {"type": "string", "minLength": 1},
|
||||
"primary_specialty": {"type": "string", "minLength": 1},
|
||||
"deployment_lane": {"type": "string", "minLength": 1},
|
||||
"allowed_autonomy": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"must_delegate_to": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"blocked_actions": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"learning_scope": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"domains": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["domain_id", "display_name", "description"],
|
||||
"properties": {
|
||||
"domain_id": {"type": "string", "minLength": 1},
|
||||
"display_name": {"type": "string", "minLength": 1},
|
||||
"description": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"deployment_targets": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"target_id",
|
||||
"domain_id",
|
||||
"display_name",
|
||||
"target_type",
|
||||
"primary_agent",
|
||||
"supporting_agents",
|
||||
"deployment_state",
|
||||
"automation_level",
|
||||
"capabilities",
|
||||
"telegram_policy",
|
||||
"learning_inputs",
|
||||
"communication_channels",
|
||||
"approval_gate",
|
||||
"evidence_refs",
|
||||
"next_action"
|
||||
],
|
||||
"properties": {
|
||||
"target_id": {"type": "string", "minLength": 1},
|
||||
"domain_id": {"type": "string", "minLength": 1},
|
||||
"display_name": {"type": "string", "minLength": 1},
|
||||
"target_type": {"type": "string", "minLength": 1},
|
||||
"primary_agent": {"type": "string", "minLength": 1},
|
||||
"supporting_agents": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"deployment_state": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"active_governed",
|
||||
"read_only_layout",
|
||||
"blocked_by_gate",
|
||||
"planned",
|
||||
"candidate_only"
|
||||
]
|
||||
},
|
||||
"automation_level": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"observe_only",
|
||||
"prepare_only",
|
||||
"dry_run_only",
|
||||
"hitl_execute_after_approval",
|
||||
"blocked"
|
||||
]
|
||||
},
|
||||
"capabilities": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"telegram_policy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"failure_only",
|
||||
"action_required",
|
||||
"approval_required",
|
||||
"daily_summary_only",
|
||||
"no_direct_notify"
|
||||
]
|
||||
},
|
||||
"learning_inputs": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"communication_channels": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"approval_gate": {"type": "string", "minLength": 1},
|
||||
"evidence_refs": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"next_action": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"collaboration_contract": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"message_bus",
|
||||
"audit_trail",
|
||||
"handoff_rules",
|
||||
"frontend_redaction"
|
||||
],
|
||||
"properties": {
|
||||
"message_bus": {"type": "string", "minLength": 1},
|
||||
"audit_trail": {"type": "string", "minLength": 1},
|
||||
"handoff_rules": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"frontend_redaction": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"operator_conversation_display_allowed",
|
||||
"agent_private_reasoning_display_allowed",
|
||||
"display_policy"
|
||||
],
|
||||
"properties": {
|
||||
"operator_conversation_display_allowed": {"type": "boolean", "const": false},
|
||||
"agent_private_reasoning_display_allowed": {"type": "boolean", "const": false},
|
||||
"display_policy": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"learning_contract": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"event_sources",
|
||||
"feedback_loops",
|
||||
"growth_metrics",
|
||||
"retention_policy"
|
||||
],
|
||||
"properties": {
|
||||
"event_sources": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"feedback_loops": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"growth_metrics": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"retention_policy": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"telegram_contract": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"primary_gateway",
|
||||
"bot_roles",
|
||||
"notification_classes",
|
||||
"redaction_policy",
|
||||
"e2e_validation"
|
||||
],
|
||||
"properties": {
|
||||
"primary_gateway": {"type": "string", "minLength": 1},
|
||||
"bot_roles": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"notification_classes": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"redaction_policy": {"type": "string", "minLength": 1},
|
||||
"e2e_validation": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"rollups": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"total_targets",
|
||||
"by_domain",
|
||||
"by_primary_agent",
|
||||
"by_deployment_state",
|
||||
"by_telegram_policy",
|
||||
"blocked_target_ids",
|
||||
"approval_required_target_ids"
|
||||
],
|
||||
"properties": {
|
||||
"total_targets": {"type": "integer", "minimum": 1},
|
||||
"by_domain": {"type": "object", "additionalProperties": {"type": "integer"}},
|
||||
"by_primary_agent": {"type": "object", "additionalProperties": {"type": "integer"}},
|
||||
"by_deployment_state": {"type": "object", "additionalProperties": {"type": "integer"}},
|
||||
"by_telegram_policy": {"type": "object", "additionalProperties": {"type": "integer"}},
|
||||
"blocked_target_ids": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
},
|
||||
"approval_required_target_ids": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"approval_boundaries": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"sdk_installation_allowed",
|
||||
"paid_api_call_allowed",
|
||||
"shadow_or_canary_allowed",
|
||||
"production_routing_allowed",
|
||||
"destructive_operation_allowed",
|
||||
"secret_plaintext_allowed",
|
||||
"autonomous_host_mutation_allowed",
|
||||
"telegram_direct_send_allowed"
|
||||
],
|
||||
"properties": {
|
||||
"sdk_installation_allowed": {"type": "boolean", "const": false},
|
||||
"paid_api_call_allowed": {"type": "boolean", "const": false},
|
||||
"shadow_or_canary_allowed": {"type": "boolean", "const": false},
|
||||
"production_routing_allowed": {"type": "boolean", "const": false},
|
||||
"destructive_operation_allowed": {"type": "boolean", "const": false},
|
||||
"secret_plaintext_allowed": {"type": "boolean", "const": false},
|
||||
"autonomous_host_mutation_allowed": {"type": "boolean", "const": false},
|
||||
"telegram_direct_send_allowed": {"type": "boolean", "const": false}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
Reference in New Issue
Block a user