$ cat node-template.py
O
Ontology Set Property
// Patch (merge) the properties of an existing ontology object or link and return its id.
Process
Data
#ontology#knowledge-graph#update#property#write
template.py
1"""ontology-set-property — patch the properties of an ontology object or link.23Merges ``properties`` into the object/link identified by ``target`` +4``targetId`` via the gais.ontology SDK (``Gais.ontology.set_property``). The5target id is UUID-validated here (defense in depth). Privileged IO carries the6per-execution USER_TOKEN inside the SDK — this node imports no HTTP client.7Returns the target ``id`` so it can be chained further.8"""910from __future__ import annotations1112import json13import re14import sys15import traceback16from typing import Any1718from gais import Gais1920_UUID_RE = re.compile(21 r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",22 re.IGNORECASE,23)24_TARGETS = ("object", "link")252627def _normalize_uuid(value: Any, field: str) -> str:28 """Accept a bare UUID or a ``mention://.../<uuid>`` URI; validate as UUID."""29 if not isinstance(value, str):30 raise ValueError(f"{field} must be a string, got {type(value).__name__}")31 s = value.strip()32 if "://" in s:33 s = s.rsplit("/", 1)[-1]34 if not _UUID_RE.match(s):35 raise ValueError(f"{field} is not a valid UUID: {value!r}")36 return s373839def _parse_obj(value: Any, field: str) -> dict:40 """Accept a mapping or a JSON-object string; reject anything else."""41 if value in (None, ""):42 return {}43 if isinstance(value, dict):44 return value45 if isinstance(value, str):46 parsed = json.loads(value)47 if not isinstance(parsed, dict):48 raise ValueError(f"{field} must be a JSON object")49 return parsed50 raise ValueError(f"{field} must be a JSON object")515253def process(inputs: dict[str, Any]) -> dict[str, Any]:54 target = str(inputs.get("target") or "object").strip().lower()55 if target not in _TARGETS:56 raise ValueError(f"target must be one of {list(_TARGETS)}")5758 target_id = _normalize_uuid(inputs.get("targetId"), "targetId")5960 properties = _parse_obj(inputs.get("properties"), "properties")61 if not properties:62 raise ValueError("Required input 'properties' must be a non-empty JSON object")6364 result = Gais.ontology.set_property(target=target, id=target_id, properties=properties)65 patched_id = result.get("id", target_id) if isinstance(result, dict) else target_id6667 print(f"[ontology-set-property] target={target} id={patched_id}", file=sys.stderr)6869 return {"id": patched_id}707172def main() -> None:73 try:74 envelope = json.loads(sys.stdin.read() or "{}")75 if not isinstance(envelope, dict):76 envelope = {}77 inputs = envelope.get("inputs", {}) or {}78 json.dump(process(inputs), sys.stdout)79 except Exception as e:80 print(81 json.dumps({82 "error": str(e),83 "errorType": type(e).__name__,84 "traceback": traceback.format_exc(),85 }),86 file=sys.stderr,87 )88 sys.exit(1)899091if __name__ == "__main__":92 main()$ git log --oneline
v1.0.0
HEAD
2026-08-18