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
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:
@@ -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))))
|
||||
Reference in New Issue
Block a user