imbajin commented on code in PR #382:
URL: https://github.com/apache/hugegraph-ai/pull/382#discussion_r4250381381


##########
hugegraph-llm/src/hugegraph_llm/api/thin_api.py:
##########
@@ -151,10 +151,31 @@ def graph_import_api(req: GraphImportRequest):
 
 
 @thin_router.post("/vid-embeddings/refresh", status_code=status.HTTP_200_OK, 
response_model=ThinAPIResponse)
-def vid_embeddings_refresh_api(_req: VidEmbeddingsRefreshRequest):
+def vid_embeddings_refresh_api(req: VidEmbeddingsRefreshRequest):
     if blocked := _thin_write_disabled():
         return blocked
-    return _wrap_flow_call(FlowName.UPDATE_VID_EMBEDDINGS)
+    # Keep target validation and flow execution atomic with respect to runtime
+    # graph configuration updates. The flow reads the same shared settings.
+    with runtime_config_lock:
+        expected_fields = {"expected_graph", "expected_graphspace"}
+        supplied_fields = req.model_fields_set & expected_fields
+        if supplied_fields and (
+            supplied_fields != expected_fields
+            or req.expected_graph != huge_settings.graph_name
+            or req.expected_graphspace != huge_settings.graph_space
+        ):
+            return _envelope_err(
+                "VALIDATION_ERROR",
+                "Expected graph and graphspace must match the configured 
HugeGraph target.",
+                suggestion="Provide both expected_graph and 
expected_graphspace matching the AI service target.",
+            )
+        return _wrap_flow_call(FlowName.UPDATE_VID_EMBEDDINGS)

Review Comment:
   Correction: the cached-pipeline conclusion above is incorrect. 
[`BaseNode.run()`](https://github.com/apache/hugegraph-ai/blob/bdf76543dd59cc19da4e3eb1337e2e1d1bdc8a7f/hugegraph-llm/src/hugegraph_llm/nodes/base_node.py#L60-L65)
 calls `node_init()` on every execution. 
[`FetchGraphDataNode`](https://github.com/apache/hugegraph-ai/blob/bdf76543dd59cc19da4e3eb1337e2e1d1bdc8a7f/hugegraph-llm/src/hugegraph_llm/nodes/hugegraph_node/fetch_graph_data.py#L29-L32)
 rebuilds its client/operator there, and 
[`BuildSemanticIndexNode`](https://github.com/apache/hugegraph-ai/blob/bdf76543dd59cc19da4e3eb1337e2e1d1bdc8a7f/hugegraph-llm/src/hugegraph_llm/nodes/index_node/build_semantic_index.py#L28-L36)
 rebuilds its index operator. The pinned pycgraph runtime dispatches the Python 
run override on each pipeline run.
   
   Pipeline reuse therefore does not itself retain graph A's client/index after 
switching to B. Please withdraw this particular critical blocker; pipeline 
invalidation is not justified solely by this argument. This does not dismiss 
the separate default-GraphSpace compatibility issue or physical-instance 
identity limitation.



##########
hugegraph-mcp/hugegraph_mcp/tools/refresh_vid_embeddings.py:
##########
@@ -41,7 +42,42 @@ def refresh_vid_embeddings(confirm: bool = False) -> 
dict[str, Any]:
             suggestion="Pass confirm=True to refresh VID embeddings.",
         )
 
-    ai_result = post("/vid-embeddings/refresh", json={})
+    cfg = MCPConfig.from_env()
+    capability = get("/vid-embeddings/refresh-capabilities", cfg=cfg)
+    if not capability.get("ok"):
+        error = capability.get("error") or {}
+        # Only an explicitly absent/unsupported endpoint means the protocol is
+        # unavailable. Keep transient and authentication errors retryable as
+        # reported by the client, without ever dispatching the refresh.
+        status_code = (error.get("details") or {}).get("status_code")
+        if error.get("type") in {
+            "AUTHENTICATION_FAILED",
+            "AUTHORIZATION_FAILED",
+            "FEATURE_DISABLED",
+        } or status_code not in {404, 405}:
+            return capability
+        return envelope_err(
+            ErrorType.FEATURE_DISABLED,
+            "AI refresh target-validation endpoint is unavailable; refresh was 
not sent.",
+            suggestion="Check the AI service URL and routing, or upgrade 
HugeGraph-AI to support target validation.",
+            details={"status_code": status_code},
+        )
+    support = capability.get("data")
+    if (
+        not isinstance(support, dict)
+        or type(support.get("protocol_version")) is not int
+        or support["protocol_version"] != 1
+    ):
+        return envelope_err(
+            ErrorType.FEATURE_DISABLED,
+            "AI refresh target-validation protocol is unsupported; refresh was 
not sent.",
+            suggestion="Upgrade HugeGraph-AI to a compatible target-validation 
version.",
+        )
+    ai_result = post(
+        "/vid-embeddings/refresh",
+        cfg=cfg,
+        json={"expected_graph": cfg.graph, "expected_graphspace": 
cfg.graphspace},

Review Comment:
   The instance-identity limitation is real, but the impact should be stated 
precisely. This flow reads IDs/schema from HugeGraph and updates the configured 
VID vector index; it does not write graph records. If the URLs identify 
different instances with the same graph/graphspace names, it can read the 
unintended instance and rebuild the vector index from that data.
   
   The independent URLs already existed on the base branch, and this PR 
documents the remaining operator responsibility. Keep this as an explicit 
safety boundary and follow-up design requirement, rather than describing it as 
a newly introduced graph-database write regression.



##########
hugegraph-llm/src/hugegraph_llm/api/thin_api.py:
##########
@@ -151,10 +151,31 @@ def graph_import_api(req: GraphImportRequest):
 
 
 @thin_router.post("/vid-embeddings/refresh", status_code=status.HTTP_200_OK, 
response_model=ThinAPIResponse)
-def vid_embeddings_refresh_api(_req: VidEmbeddingsRefreshRequest):
+def vid_embeddings_refresh_api(req: VidEmbeddingsRefreshRequest):
     if blocked := _thin_write_disabled():
         return blocked
-    return _wrap_flow_call(FlowName.UPDATE_VID_EMBEDDINGS)
+    # Keep target validation and flow execution atomic with respect to runtime
+    # graph configuration updates. The flow reads the same shared settings.
+    with runtime_config_lock:
+        expected_fields = {"expected_graph", "expected_graphspace"}
+        supplied_fields = req.model_fields_set & expected_fields
+        if supplied_fields and (
+            supplied_fields != expected_fields
+            or req.expected_graph != huge_settings.graph_name
+            or req.expected_graphspace != huge_settings.graph_space

Review Comment:
   Confirmed by independent source tracing: MCP normalizes missing graphspace 
to `DEFAULT`, while AI settings can remain `None` or blank and the new 
comparison rejects the equivalent target. Normalize the effective identity 
without changing the existing index-path convention, and cover 
unset/blank/explicit DEFAULT as well as genuinely different non-default spaces.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to