499 lines
19 KiB
Python
499 lines
19 KiB
Python
"""Read-only inventory for external MCP/RAG absorption into internal control planes."""
|
||
|
||
from __future__ import annotations
|
||
|
||
import os
|
||
import hashlib
|
||
import json
|
||
from copy import deepcopy
|
||
from datetime import datetime, timezone
|
||
from typing import Any
|
||
from zoneinfo import ZoneInfo
|
||
|
||
|
||
POLICY = "read_only_external_mcp_rag_integration_readback_v1"
|
||
PUBLIC_FEDERATION_SCHEMA_VERSION = "ewoooc_mcp_federation_receipt_v1"
|
||
PUBLIC_FEDERATION_POLICY = "public_aggregate_read_only_mcp_federation_v1"
|
||
TAIPEI_TZ = ZoneInfo("Asia/Taipei")
|
||
|
||
_FEDERATED_PRODUCTS = (
|
||
{
|
||
"product_id": "ewoooc",
|
||
"canonical_repo": "wooo/ewoooc",
|
||
"runtime_role": "mcp_rag_automation_source_plane",
|
||
},
|
||
{
|
||
"product_id": "momo-pro-system",
|
||
"canonical_repo": "wooo/momo-pro-system",
|
||
"runtime_role": "commerce_runtime_consumer_plane",
|
||
},
|
||
)
|
||
|
||
|
||
def _enabled(value: str | None) -> bool:
|
||
return str(value or "").strip().lower() in {"1", "true", "yes", "on"}
|
||
|
||
|
||
def _controlled_apply_boundary() -> dict[str, bool]:
|
||
return {
|
||
"network_call": False,
|
||
"db_write": False,
|
||
"secret_read": False,
|
||
"production_price_write": False,
|
||
"external_side_effect": False,
|
||
}
|
||
|
||
|
||
def _public_operation_boundaries() -> dict[str, bool]:
|
||
"""V-New: 公開 receipt 只允許無副作用的聚合狀態讀回。"""
|
||
return {
|
||
"read_only_observation_allowed": True,
|
||
"network_call_allowed": False,
|
||
"db_write_allowed": False,
|
||
"secret_read_allowed": False,
|
||
"external_tool_call_allowed": False,
|
||
"rag_write_allowed": False,
|
||
"production_price_write_allowed": False,
|
||
"request_or_response_body_storage_allowed": False,
|
||
}
|
||
|
||
|
||
def _safe_mcp_summary(snapshot: dict[str, Any]) -> dict[str, Any]:
|
||
servers = snapshot.get("servers")
|
||
servers = servers if isinstance(servers, dict) else {}
|
||
registry = snapshot.get("tool_registry")
|
||
registry = registry if isinstance(registry, dict) else {}
|
||
tool_count = 0
|
||
for server_map in registry.values():
|
||
if not isinstance(server_map, dict):
|
||
continue
|
||
for tools in server_map.values():
|
||
if isinstance(tools, (list, tuple, set)):
|
||
tool_count += len(tools)
|
||
return {
|
||
"enabled": snapshot.get("enabled") is True,
|
||
"server_count": len(servers),
|
||
"server_ids": sorted(str(server_id) for server_id in servers),
|
||
"caller_count": int(snapshot.get("caller_count") or 0),
|
||
"tool_count": tool_count,
|
||
}
|
||
|
||
|
||
def _safe_rag_summary(snapshot: dict[str, Any]) -> dict[str, Any]:
|
||
model = str(snapshot.get("embedding_model") or "")
|
||
return {
|
||
"enabled": snapshot.get("enabled") is True,
|
||
"vector_store": str(snapshot.get("vector_store") or "pgvector"),
|
||
"embedding_model": model,
|
||
"embedding_dim": int(snapshot.get("embedding_dim") or 0),
|
||
"embedding_signature": str(snapshot.get("embedding_signature") or ""),
|
||
"embedding_version_state": (
|
||
"floating_tag_detected" if model.endswith(":latest") else "explicit_or_unknown"
|
||
),
|
||
}
|
||
|
||
|
||
def _safe_pixelrag_summary(snapshot: dict[str, Any]) -> dict[str, Any]:
|
||
return {
|
||
"enabled": snapshot.get("enabled") is True,
|
||
"platform_count": int(snapshot.get("platform_count") or 0),
|
||
"platforms": sorted(
|
||
str(platform) for platform in snapshot.get("platforms") or []
|
||
),
|
||
"visual_rag_stage": str(
|
||
snapshot.get("visual_rag_stage") or "unavailable"
|
||
),
|
||
"formal_product_write_allowed": False,
|
||
}
|
||
|
||
|
||
def compute_public_federation_receipt_fingerprint(
|
||
receipt: dict[str, Any],
|
||
) -> str:
|
||
"""Return the verifier-recomputable hash for normalized public fields."""
|
||
covered = {
|
||
key: value
|
||
for key, value in receipt.items()
|
||
if key not in {"receipt_id", "observed_at", "integrity"}
|
||
}
|
||
canonical = json.dumps(
|
||
covered,
|
||
ensure_ascii=False,
|
||
sort_keys=True,
|
||
separators=(",", ":"),
|
||
)
|
||
return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
|
||
|
||
|
||
def build_public_mcp_federation_receipt(
|
||
*,
|
||
runtime_version: str,
|
||
observed_at: str | None = None,
|
||
) -> dict[str, Any]:
|
||
"""Build two product-scoped, aggregate-only MCP/RAG runtime receipts.
|
||
|
||
This function performs no network call, database read/write, tool call, or
|
||
RAG write. Internal endpoint URLs and raw tool registries are deliberately
|
||
reduced to stable IDs and counts before reaching the public response.
|
||
"""
|
||
timestamp = observed_at or datetime.now(TAIPEI_TZ).isoformat(timespec="seconds")
|
||
mcp = _safe_mcp_summary(_mcp_runtime_snapshot())
|
||
rag = _safe_rag_summary(_rag_runtime_snapshot())
|
||
pixelrag = _safe_pixelrag_summary(_pixelrag_snapshot())
|
||
|
||
blockers: list[str] = []
|
||
if not mcp["enabled"]:
|
||
blockers.append("mcp_router_runtime_not_enabled")
|
||
if mcp["server_count"] == 0 or mcp["tool_count"] == 0:
|
||
blockers.append("mcp_runtime_inventory_empty")
|
||
if not rag["enabled"]:
|
||
blockers.append("rag_runtime_not_enabled")
|
||
if not rag["embedding_signature"]:
|
||
blockers.append("rag_embedding_signature_missing")
|
||
if rag["embedding_version_state"] == "floating_tag_detected":
|
||
blockers.append("rag_embedding_model_not_immutable")
|
||
if not pixelrag["enabled"]:
|
||
blockers.append("pixelrag_runtime_not_enabled")
|
||
blockers = sorted(blockers)
|
||
|
||
normalized_runtime = {
|
||
"mcp": mcp,
|
||
"rag": rag,
|
||
"pixelrag": pixelrag,
|
||
}
|
||
receipts: list[dict[str, Any]] = []
|
||
for product in _FEDERATED_PRODUCTS:
|
||
receipt: dict[str, Any] = {
|
||
"receipt_schema_version": PUBLIC_FEDERATION_SCHEMA_VERSION,
|
||
"product_id": product["product_id"],
|
||
"canonical_repo": product["canonical_repo"],
|
||
"runtime_role": product["runtime_role"],
|
||
"runtime_version": str(runtime_version or "unknown"),
|
||
"health_status": "ready" if not blockers else "partial_degraded",
|
||
"runtime": deepcopy(normalized_runtime),
|
||
"data_boundaries": {
|
||
"scope": "aggregate_runtime_metadata_only",
|
||
"pixelrag": "public_visual_receipts_no_formal_product_write",
|
||
"rag": "pgvector_internal_only_no_public_content",
|
||
"mcp": "server_ids_and_counts_only_no_endpoint_or_payload",
|
||
},
|
||
"operation_boundaries": _public_operation_boundaries(),
|
||
"blockers": list(blockers),
|
||
}
|
||
fingerprint = compute_public_federation_receipt_fingerprint(receipt)
|
||
receipt["observed_at"] = timestamp
|
||
receipt["receipt_id"] = (
|
||
f"mcp-federation:{product['product_id']}:{fingerprint[:16]}"
|
||
)
|
||
receipt["integrity"] = {
|
||
"algorithm": "sha256",
|
||
"canonicalization": "json_sort_keys_compact_v1",
|
||
"excluded_fields": ["receipt_id", "observed_at", "integrity"],
|
||
"normalized_fingerprint_sha256": fingerprint,
|
||
}
|
||
receipts.append(receipt)
|
||
|
||
return {
|
||
"success": True,
|
||
"schema_version": PUBLIC_FEDERATION_SCHEMA_VERSION,
|
||
"policy": PUBLIC_FEDERATION_POLICY,
|
||
"generated_at": timestamp,
|
||
"status": "ready" if not blockers else "partial_degraded",
|
||
"receipt_count": len(receipts),
|
||
"receipts": receipts,
|
||
"blockers": blockers,
|
||
"operation_boundaries": _public_operation_boundaries(),
|
||
"next_machine_action": (
|
||
"pin_embedding_model_and_verify_runtime_receipts"
|
||
if blockers
|
||
else "continue_scheduled_read_only_federation"
|
||
),
|
||
}
|
||
|
||
|
||
def _status_counts(items: list[dict[str, Any]]) -> dict[str, int]:
|
||
counts: dict[str, int] = {}
|
||
for item in items:
|
||
status = str(item.get("status") or "unknown")
|
||
counts[status] = counts.get(status, 0) + 1
|
||
return counts
|
||
|
||
|
||
def _mcp_runtime_snapshot() -> dict[str, Any]:
|
||
try:
|
||
from services.mcp_router import MCP_BASE_HOSTS, TOOL_REGISTRY, is_mcp_router_enabled
|
||
|
||
return {
|
||
"enabled": is_mcp_router_enabled(),
|
||
"servers": deepcopy(MCP_BASE_HOSTS),
|
||
"caller_count": len(TOOL_REGISTRY),
|
||
"tool_registry": {
|
||
caller: {
|
||
server: list(tools)
|
||
for server, tools in servers.items()
|
||
}
|
||
for caller, servers in TOOL_REGISTRY.items()
|
||
},
|
||
}
|
||
except Exception as exc:
|
||
return {
|
||
"enabled": False,
|
||
"servers": {},
|
||
"caller_count": 0,
|
||
"tool_registry": {},
|
||
"error": str(exc)[:300],
|
||
}
|
||
|
||
|
||
def _rag_runtime_snapshot() -> dict[str, Any]:
|
||
try:
|
||
from services.rag_service import (
|
||
RAG_DEFAULT_THRESHOLD,
|
||
RAG_DEFAULT_TOP_K,
|
||
RAG_EMBED_DIM,
|
||
RAG_EMBED_MODEL,
|
||
get_embedding_signature,
|
||
is_rag_enabled,
|
||
)
|
||
|
||
return {
|
||
"enabled": is_rag_enabled(),
|
||
"vector_store": "pgvector",
|
||
"embedding_model": RAG_EMBED_MODEL,
|
||
"embedding_dim": RAG_EMBED_DIM,
|
||
"embedding_signature": get_embedding_signature(),
|
||
"default_top_k": RAG_DEFAULT_TOP_K,
|
||
"default_threshold": RAG_DEFAULT_THRESHOLD,
|
||
}
|
||
except Exception as exc:
|
||
return {
|
||
"enabled": False,
|
||
"vector_store": "pgvector",
|
||
"embedding_model": "",
|
||
"embedding_dim": 0,
|
||
"embedding_signature": "",
|
||
"error": str(exc)[:300],
|
||
}
|
||
|
||
|
||
def _pixelrag_snapshot() -> dict[str, Any]:
|
||
try:
|
||
from services.pixelrag_crawler_integration_service import ECOMMERCE_PLATFORM_PROFILES
|
||
|
||
platforms = sorted(
|
||
platform
|
||
for platform in ECOMMERCE_PLATFORM_PROFILES
|
||
if platform not in {"market_intel", "external_market"}
|
||
)
|
||
return {
|
||
"enabled": True,
|
||
"platform_count": len(platforms),
|
||
"platforms": platforms,
|
||
"visual_rag_stage": "phase1_visual_evidence_receipts",
|
||
}
|
||
except Exception as exc:
|
||
return {
|
||
"enabled": False,
|
||
"platform_count": 0,
|
||
"platforms": [],
|
||
"visual_rag_stage": "unavailable",
|
||
"error": str(exc)[:300],
|
||
}
|
||
|
||
|
||
def _capability_inventory() -> list[dict[str, Any]]:
|
||
return [
|
||
{
|
||
"id": "mcp.omnisearch.tavily_exa",
|
||
"family": "external_mcp",
|
||
"external_capability": "Tavily / Exa style public web search through omnisearch MCP",
|
||
"internal_plane": "mcp_router",
|
||
"internal_entrypoint": "services.mcp_router.TOOL_REGISTRY[mcp_collector][omnisearch]",
|
||
"status": "integrated_self_hosted_gateway",
|
||
"writes": ["mcp_calls_log_async"],
|
||
"data_boundary": "public_search_summary_only",
|
||
"next_machine_action": "keep_mcp_router_health_and_cache_readback",
|
||
},
|
||
{
|
||
"id": "mcp.firecrawl.scrape",
|
||
"family": "external_mcp",
|
||
"external_capability": "Firecrawl style public page scrape",
|
||
"internal_plane": "mcp_router",
|
||
"internal_entrypoint": "services.mcp_router.TOOL_REGISTRY[*][firecrawl].scrape_url",
|
||
"status": "integrated_self_hosted_gateway",
|
||
"writes": ["mcp_calls_log_async"],
|
||
"data_boundary": "approved_public_url_only",
|
||
"next_machine_action": "enforce_source_contract_before_scheduler_attach",
|
||
},
|
||
{
|
||
"id": "mcp.postgres.query",
|
||
"family": "internal_mcp",
|
||
"external_capability": "SQL read interface exposed as MCP tool",
|
||
"internal_plane": "mcp_router",
|
||
"internal_entrypoint": "postgres.query for approved callers",
|
||
"status": "integrated_read_only_contract",
|
||
"writes": ["mcp_calls_log_async"],
|
||
"data_boundary": "read_only_query_allowlist",
|
||
"next_machine_action": "keep_disallowing_unknown_callers_and_write_tools",
|
||
},
|
||
{
|
||
"id": "mcp.filesystem.readonly",
|
||
"family": "internal_mcp",
|
||
"external_capability": "Filesystem MCP read diagnostics",
|
||
"internal_plane": "mcp_router",
|
||
"internal_entrypoint": "ops_diagnostics filesystem read-only tools",
|
||
"status": "integrated_read_only_contract",
|
||
"writes": ["mcp_calls_log_async"],
|
||
"data_boundary": "allowed_directories_read_only",
|
||
"next_machine_action": "keep_write_file_and_mutation_tools_rejected",
|
||
},
|
||
{
|
||
"id": "rag.pixelrag.visual_evidence",
|
||
"family": "external_rag",
|
||
"external_capability": "PixelRAG page screenshot and tile retrieval pattern",
|
||
"internal_plane": "pixelrag_visual_evidence + internal RAG candidate lane",
|
||
"internal_entrypoint": "services.pixelrag_crawler_integration_service",
|
||
"status": "integrated_phase1_visual_receipts",
|
||
"writes": ["artifact_file_only"],
|
||
"data_boundary": "public_page_screenshot_tiles_no_price_write",
|
||
"next_machine_action": "add_ocr_vlm_replay_before_promoting_to_pgvector_rag",
|
||
},
|
||
{
|
||
"id": "rag.pgvector.bge_m3",
|
||
"family": "internal_rag",
|
||
"external_capability": "General text RAG retrieval pattern",
|
||
"internal_plane": "rag_service",
|
||
"internal_entrypoint": "services.rag_service.RAGService.query",
|
||
"status": "internal_primary_ready",
|
||
"writes": ["rag_query_log_async"],
|
||
"data_boundary": "ai_insights_pgvector_embedding_signature_guard",
|
||
"next_machine_action": "keep_embedding_signature_and_feedback_guardrails",
|
||
},
|
||
{
|
||
"id": "rag.qwen3_vl_embedding",
|
||
"family": "external_rag",
|
||
"external_capability": "Multimodal visual embedding model for tile retrieval",
|
||
"internal_plane": "ollama_first_visual_embedding_benchmark",
|
||
"internal_entrypoint": "not_enabled_in_production",
|
||
"status": "deferred_until_ollama_first_verified",
|
||
"writes": [],
|
||
"data_boundary": "no_hosted_visual_embedding_api",
|
||
"next_machine_action": "benchmark_local_multimodal_embedding_then_design_pgvector_metadata",
|
||
},
|
||
{
|
||
"id": "rag.faiss_visual_index",
|
||
"family": "external_rag",
|
||
"external_capability": "FAISS visual retrieval index used by some PixelRAG pipelines",
|
||
"internal_plane": "pgvector_first_policy",
|
||
"internal_entrypoint": "not_enabled_in_production",
|
||
"status": "rejected_for_production_without_adr",
|
||
"writes": [],
|
||
"data_boundary": "pgvector_is_the_only_production_vector_store",
|
||
"next_machine_action": "use_pgvector_compatible_metadata_or_write_adr_before_any_faiss_trial",
|
||
},
|
||
{
|
||
"id": "mcp.gemini_grounding",
|
||
"family": "external_mcp",
|
||
"external_capability": "Gemini grounding as hosted external search fallback",
|
||
"internal_plane": "mcp_collector_final_fallback",
|
||
"internal_entrypoint": "services.mcp_collector_service guarded fallback",
|
||
"status": "disabled_by_default_fallback_only",
|
||
"writes": ["mcp_cache_only_when_explicitly_enabled"],
|
||
"data_boundary": "gemini_api_hard_disabled_by_default",
|
||
"next_machine_action": "prefer_self_hosted_mcp_or_ollama_static_fallback",
|
||
},
|
||
]
|
||
|
||
|
||
def build_external_mcp_rag_integration_readback(
|
||
*,
|
||
target_family: str | None = None,
|
||
) -> dict[str, Any]:
|
||
"""Describe how external MCP/RAG capabilities are absorbed internally."""
|
||
family_filter = str(target_family or "").strip().lower()
|
||
inventory = _capability_inventory()
|
||
if family_filter:
|
||
inventory = [
|
||
item
|
||
for item in inventory
|
||
if str(item.get("family") or "").lower() == family_filter
|
||
]
|
||
|
||
counts = _status_counts(inventory)
|
||
unresolved = [
|
||
item
|
||
for item in inventory
|
||
if str(item.get("status") or "").startswith(("deferred", "rejected", "disabled"))
|
||
]
|
||
absorbed = [
|
||
item
|
||
for item in inventory
|
||
if item not in unresolved
|
||
]
|
||
all_absorbed = len(unresolved) == 0
|
||
|
||
return {
|
||
"success": True,
|
||
"policy": POLICY,
|
||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||
"status": "partially_integrated" if not all_absorbed else "fully_integrated",
|
||
"answer_to_owner": (
|
||
"不是全部完成;已把主要外部 MCP/RAG 放進內部可治理 registry,"
|
||
"其中 self-hosted MCP、pgvector RAG、PixelRAG phase1 已整合,"
|
||
"多模態 embedding / FAISS / Gemini grounding 仍需條件或維持停用。"
|
||
if not all_absorbed
|
||
else "目前 registry 內的外部 MCP/RAG 都已有內部治理落點。"
|
||
),
|
||
"completion": {
|
||
"total_capabilities": len(inventory),
|
||
"absorbed_count": len(absorbed),
|
||
"unresolved_count": len(unresolved),
|
||
"all_absorbed": all_absorbed,
|
||
"status_counts": counts,
|
||
},
|
||
"runtime": {
|
||
"mcp": _mcp_runtime_snapshot(),
|
||
"rag": _rag_runtime_snapshot(),
|
||
"pixelrag": _pixelrag_snapshot(),
|
||
"env_flags": {
|
||
"MCP_ROUTER_ENABLED": _enabled(os.getenv("MCP_ROUTER_ENABLED")),
|
||
"RAG_ENABLED": _enabled(os.getenv("RAG_ENABLED")),
|
||
"GEMINI_API_HARD_DISABLED": _enabled(os.getenv("GEMINI_API_HARD_DISABLED", "true")),
|
||
},
|
||
},
|
||
"inventory": inventory,
|
||
"next_machine_actions": [
|
||
{
|
||
"priority": "P0",
|
||
"action": "wire_pixelrag_receipts_to_internal_rag_candidate_replay",
|
||
"status": "ready_after_ocr_vlm_replay_contract",
|
||
},
|
||
{
|
||
"priority": "P0",
|
||
"action": "add_mcp_router_health_readback_to_ai_automation_smoke",
|
||
"status": "ready",
|
||
},
|
||
{
|
||
"priority": "P1",
|
||
"action": "benchmark_ollama_first_visual_embedding",
|
||
"status": "blocked_until_model_runtime_verified",
|
||
},
|
||
{
|
||
"priority": "P1",
|
||
"action": "promote_successful_marketplace_visual_receipts_to_source_contracts",
|
||
"status": "ready_for_shopee_warning_for_coupang",
|
||
},
|
||
],
|
||
"controlled_apply": _controlled_apply_boundary(),
|
||
}
|
||
|
||
|
||
__all__ = [
|
||
"POLICY",
|
||
"PUBLIC_FEDERATION_POLICY",
|
||
"PUBLIC_FEDERATION_SCHEMA_VERSION",
|
||
"build_external_mcp_rag_integration_readback",
|
||
"build_public_mcp_federation_receipt",
|
||
"compute_public_federation_receipt_fingerprint",
|
||
]
|