$ 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