feat(api): expose agent log intelligence readback
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled

This commit is contained in:
Your Name
2026-06-29 20:24:19 +08:00
parent 094f50ddbd
commit c1337fea77
3 changed files with 373 additions and 0 deletions

View File

@@ -0,0 +1,228 @@
"""AI Agent log intelligence integration readback.
This service exposes a source-of-truth map for LOG -> KM/RAG/MCP/PlayBook
automation. It only inspects committed source files packaged with the API image;
it does not query live logs, read secrets, write KM, update PlayBook trust,
call MCP tools, trigger workflows, or execute runtime repairs.
"""
from __future__ import annotations
from pathlib import Path
from typing import Any
from src.services.snapshot_paths import resolve_repo_root
_SCHEMA_VERSION = "ai_agent_log_intelligence_integration_readback_v1"
_DEFAULT_REPO_ROOT = resolve_repo_root(Path(__file__))
_LANES: tuple[dict[str, Any], ...] = (
{
"lane_id": "structured_service_log_collection",
"title": "服務日誌與可觀測性來源",
"source_kind": "logs_metrics_traces",
"integration_target": "diagnosis_context",
"required_refs": (
"apps/api/src/core/logging.py",
"apps/api/src/core/deep_linking.py",
"apps/api/src/services/diagnosis_aggregator.py",
),
"required_labels": ("project_id", "service", "environment", "trace_id", "severity"),
},
{
"lane_id": "log_classification_summary",
"title": "Log 分類、摘要與異常訊號",
"source_kind": "log_classification",
"integration_target": "agent_evidence_packet",
"required_refs": (
"apps/api/src/services/log_anomaly_detector.py",
"apps/api/src/services/log_summary_service.py",
"apps/api/src/services/diagnosis_aggregator.py",
),
"required_labels": ("signal_kind", "severity", "service", "package", "tool"),
},
{
"lane_id": "km_rag_consumption",
"title": "KM / RAG 證據消費",
"source_kind": "knowledge_memory",
"integration_target": "rag_context",
"required_refs": (
"apps/api/src/services/knowledge_extractor_service.py",
"apps/api/src/services/knowledge_service.py",
"apps/api/src/services/knowledge_rag_service.py",
"apps/api/src/services/rag_service.py",
"apps/api/src/services/graph_rag.py",
),
"required_labels": ("project_id", "product", "service", "incident_id", "evidence_ref"),
},
{
"lane_id": "playbook_learning_loop",
"title": "PlayBook 匹配、RAG 與 trust 學習",
"source_kind": "playbook_learning",
"integration_target": "playbook_candidate_and_trust_gate",
"required_refs": (
"apps/api/src/services/playbook_rag.py",
"apps/api/src/services/playbook_match_resolver.py",
"apps/api/src/services/playbook_embedding_service.py",
"apps/api/src/services/playbook_evolver.py",
"apps/api/src/services/ai_agent_matched_playbook_learning_gap.py",
),
"required_labels": ("playbook_id", "incident_id", "service", "risk_tier", "verifier_id"),
},
{
"lane_id": "mcp_tool_audit_context",
"title": "MCP 工具、稽核上下文與工具註冊",
"source_kind": "mcp_tools",
"integration_target": "controlled_tool_context",
"required_refs": (
"apps/api/src/plugins/mcp/mcp_bridge.py",
"apps/api/src/services/mcp_audit_context.py",
"apps/api/src/services/mcp_audit_service.py",
"apps/api/src/services/mcp_tool_registry.py",
),
"required_labels": ("mcp_server", "tool", "agent_run_id", "gateway_path", "redaction_state"),
},
{
"lane_id": "agent_decision_runtime_context",
"title": "AI Agent 決策與結果捕獲",
"source_kind": "agent_runtime",
"integration_target": "controlled_decision_runtime",
"required_refs": (
"apps/api/src/services/ai_agent_autonomous_runtime_control.py",
"apps/api/src/services/ai_agent_task_result_audit_trail.py",
"apps/api/src/services/ai_agent_result_capture_writer_dry_run_readback.py",
"apps/api/src/services/ai_agent_result_capture_no_write_readback.py",
),
"required_labels": ("agent_run_id", "decision_id", "risk_tier", "source_system", "verifier_id"),
},
{
"lane_id": "post_apply_verifier_feedback",
"title": "Verifier 與 post-apply feedback",
"source_kind": "verification_feedback",
"integration_target": "learning_writeback_candidate",
"required_refs": (
"apps/api/src/services/ai_agent_runtime_verifier_evidence_review.py",
"apps/api/src/services/ai_agent_post_write_verifier_package.py",
"apps/api/src/services/ai_agent_result_capture_post_release_verifier_rollback_gate.py",
),
"required_labels": ("verifier_id", "rollback_ref", "service", "environment", "decision_id"),
},
)
_LABEL_TAXONOMY: tuple[dict[str, Any], ...] = (
{
"label_group": "ownership",
"required_fields": ("project_id", "product", "service", "owner_lane"),
"purpose": "把所有 log / event 綁回專案、產品、服務與 owner lane。",
},
{
"label_group": "runtime_surface",
"required_fields": ("environment", "host", "package", "tool", "source_system"),
"purpose": "把網站、服務、套件、工具與主機來源分群。",
},
{
"label_group": "correlation",
"required_fields": ("trace_id", "incident_id", "agent_run_id", "decision_id"),
"purpose": "把 log、告警、AI run、AwoooP work item 與 verifier 串成同一條證據鏈。",
},
{
"label_group": "learning",
"required_fields": ("playbook_id", "verifier_id", "risk_tier", "redaction_state"),
"purpose": "讓 KM/RAG/PlayBook trust writeback 能判斷是否可學習。",
},
)
def load_latest_ai_agent_log_intelligence_integration_readback(
repo_root: Path | None = None,
) -> dict[str, Any]:
"""Build the latest LOG -> AI automation integration readback."""
root = repo_root or _DEFAULT_REPO_ROOT
lanes = [_build_lane(root, lane) for lane in _LANES]
ready_lane_count = sum(1 for lane in lanes if lane["status"] == "source_refs_present")
missing_lane_count = len(lanes) - ready_lane_count
label_field_count = len(
{field for group in _LABEL_TAXONOMY for field in group["required_fields"]}
)
active_blockers = []
if missing_lane_count:
active_blockers.append("committed_source_refs_missing")
active_blockers.append("runtime_e2e_log_sample_readback_missing")
return {
"schema_version": _SCHEMA_VERSION,
"priority": "P1-LOG-KM-RAG-MCP-PLAYBOOK",
"scope": "ai_agent_log_intelligence_integration",
"status": (
"controlled_apply_ready_missing_runtime_e2e_log_sample"
if not missing_lane_count
else "blocked_missing_committed_source_refs"
),
"readback": {
"workplan_id": "P1-LOG-INTELLIGENCE",
"workplan_title": "所有服務日誌貼標並串接 KM / RAG / MCP / PlayBook / AI Agent",
"repo_root_ref": str(root),
"safe_next_step": (
"add_runtime_log_sample_verifier_then_write_trusted_KM_RAG_PlayBook_feedback_receipt"
),
},
"integration_lanes": lanes,
"label_taxonomy": list(_LABEL_TAXONOMY),
"rollups": {
"lane_count": len(lanes),
"ready_lane_count": ready_lane_count,
"missing_lane_count": missing_lane_count,
"source_ref_count": sum(len(lane["evidence_refs"]) for lane in lanes),
"missing_source_ref_count": sum(len(lane["missing_refs"]) for lane in lanes),
"readiness_percent": _percent(ready_lane_count / max(len(lanes), 1) * 100),
"label_group_count": len(_LABEL_TAXONOMY),
"required_label_field_count": label_field_count,
"runtime_e2e_log_sample_readback_present": False,
"km_rag_playbook_trust_writeback_authorized": False,
"mcp_tool_execution_authorized": False,
},
"active_blockers": active_blockers,
"operation_boundaries": {
"read_only_api_allowed": True,
"live_log_query_performed": False,
"km_write_performed": False,
"rag_index_write_performed": False,
"playbook_trust_write_performed": False,
"mcp_tool_call_performed": False,
"runtime_repair_performed": False,
"workflow_trigger_performed": False,
"secret_value_collection_allowed": False,
"raw_session_or_sqlite_read_allowed": False,
"github_api_used": False,
},
}
def _build_lane(root: Path, lane: dict[str, Any]) -> dict[str, Any]:
evidence_refs = [str(ref) for ref in lane["required_refs"]]
missing_refs = [ref for ref in evidence_refs if not _ref_exists(root, ref)]
return {
"lane_id": lane["lane_id"],
"title": lane["title"],
"source_kind": lane["source_kind"],
"integration_target": lane["integration_target"],
"status": "source_refs_present" if not missing_refs else "missing_source_refs",
"required_labels": list(lane["required_labels"]),
"evidence_refs": evidence_refs,
"missing_refs": missing_refs,
"controlled_apply_next_step": "attach_runtime_sample_and_post_apply_verifier",
"runtime_write_enabled": False,
"secret_value_collection_allowed": False,
}
def _ref_exists(root: Path, ref: str) -> bool:
if (root / ref).exists():
return True
if ref.startswith("apps/api/"):
return (root / ref.removeprefix("apps/api/")).exists()
return False
def _percent(value: Any) -> int:
return max(0, min(100, round(float(value or 0))))