{
  "kind": "documentation",
  "format": 1,
  "note": "Reference text, not instructions. One verified relate sample from https://relatedb.ai/docs/guides/integrations/openai-agents-sdk/: the program exactly as the page shows it, the standard output a run of it recorded (npm run docs:samples compares every replay with it byte for byte), the relate client build, toolchain and platform of the last replay, and how the docs' sample runner builds and runs it. Before launch every client is a source build, not a published package; verified.client names the upstream commit it was built from, and verified.docs_engine the build the rest of the docs were recorded from.",
  "id": "graph-tool",
  "url": "https://relatedb.ai/docs/guides/integrations/openai-agents-sdk/samples/graph-tool.json",
  "page": {
    "id": "guides/integrations/openai-agents-sdk",
    "title": "Use relate with the OpenAI Agents SDK",
    "url": "https://relatedb.ai/docs/guides/integrations/openai-agents-sdk/",
    "md_url": "https://relatedb.ai/docs/guides/integrations/openai-agents-sdk.md"
  },
  "section": {
    "anchor": "write-the-tool",
    "heading": "Write the tool",
    "url": "https://relatedb.ai/docs/guides/integrations/openai-agents-sdk/#write-the-tool"
  },
  "language": "python",
  "client": "Python",
  "file": "graph_tool.py",
  "env": null,
  "code": "import asyncio\nimport json\n\nimport relate\nfrom agents import function_tool\nfrom agents.tool_context import ToolContext\nfrom pydantic import BaseModel, Field\n\nTEAM = \"\"\"\nCREATE (ada:Person {name: 'Ada', role: 'engineer'}),\n       (grace:Person {name: 'Grace', role: 'engineer'}),\n       (noor:Person {name: 'Noor', role: 'maintainer'}),\n       (relate:Project {name: 'relate', language: 'Rust'}),\n       (tck:Project {name: 'opencypher-tck', language: 'Gherkin'}),\n       (ada)-[:WORKS_ON {since: 2024}]->(relate),\n       (grace)-[:WORKS_ON {since: 2023}]->(relate),\n       (grace)-[:WORKS_ON {since: 2022}]->(tck),\n       (noor)-[:MAINTAINS]->(relate),\n       (ada)-[:KNOWS]->(grace)\n\"\"\"\n\nSTORE = \"./team\"\nMAX_ROWS = 50\n\n# Setup: the app that owns ./team writes the team graph once, on a writable connection.\nwith relate.connect(STORE) as owner:\n    if owner.execute(\"MATCH (p:Person) RETURN count(p) AS n\").single()[\"n\"] == 0:\n        owner.execute(TEAM)\n\n\nclass Param(BaseModel):\n    name: str = Field(description=\"The parameter's name, without the $\")\n    value: str | int | float | bool\n\n\n@function_tool\ndef read_graph(statement: str, params: list[Param]) -> str:\n    \"\"\"Run one read-only Cypher statement against the team graph and return its rows as JSON.\n\n    The graph has Person and Project nodes and WORKS_ON, MAINTAINS and KNOWS relationships.\n\n    Args:\n        statement: One Cypher statement that only reads.\n        params: Values for the statement's $parameters.\n    \"\"\"\n    values = {p.name: p.value for p in params}\n    try:\n        # Read-only: the engine refuses every write on this connection.\n        with relate.connect(STORE, read_only=True) as conn:\n            # EXPLAIN plans the statement without running it; query type \"r\" is a pure read.\n            kind = conn.execute(f\"EXPLAIN {statement}\", values).consume().query_type\n            if kind != \"r\":\n                return json.dumps({\"error\": f'refused: the statement\\'s query type is \"{kind}\", and this tool runs only reads (\"r\")'})\n            cur = conn.execute(statement, values)\n            rows = [row.data() for row in cur.fetchmany(MAX_ROWS + 1)]\n    except relate.Error as e:\n        return json.dumps({\"error\": str(e), \"gql_status\": e.gql_status})\n    return json.dumps({\"columns\": cur.columns, \"rows\": rows[:MAX_ROWS], \"truncated\": len(rows) > MAX_ROWS}, default=str)\n\n\nasync def call(tool, arguments: dict) -> str:\n    \"\"\"Invoke a function tool the way the Runner does, without a model.\"\"\"\n    args = json.dumps(arguments)\n    ctx = ToolContext(context=None, tool_name=tool.name, tool_call_id=\"check\", tool_arguments=args)\n    return await tool.on_invoke_tool(ctx, args)\n\n\n# Check: what the model sees, then three calls.\nprint(read_graph.name, json.dumps(read_graph.params_json_schema[\"required\"]))\nprint(asyncio.run(call(read_graph, {\n    \"statement\": \"MATCH (p:Person)-[w:WORKS_ON]->(:Project {name: $project}) RETURN p.name AS name, w.since AS since ORDER BY since\",\n    \"params\": [{\"name\": \"project\", \"value\": \"relate\"}],\n})))\nprint(asyncio.run(call(read_graph, {\n    \"statement\": \"MATCH (p:Person {name: $name}) DETACH DELETE p\",\n    \"params\": [{\"name\": \"name\", \"value\": \"Ada\"}],\n})))\nprint(asyncio.run(call(read_graph, {\"statement\": \"MATCH (p:Person {name: $name}) RETURN p.role AS role\", \"params\": []})))\n\nwith relate.connect(STORE, read_only=True) as conn:\n    print(\"people:\", conn.execute(\"MATCH (p:Person) RETURN count(p) AS people\").single()[\"people\"])",
  "code_sha256": "69d5c995edcf704ce17fe1ab9885ae0d6c5682f41acd7ffbc4f58e9a2beee345",
  "source_sha256": "224b3ced3f141d4b0d3f8e9204b6b4af694d99b86ba2d600e23b651860140ac5",
  "output": {
    "text": "read_graph [\"statement\", \"params\"]\n{\"columns\": [\"name\", \"since\"], \"rows\": [{\"name\": \"Grace\", \"since\": 2023}, {\"name\": \"Ada\", \"since\": 2024}], \"truncated\": false}\n{\"error\": \"refused: the statement's query type is \\\"w\\\", and this tool runs only reads (\\\"r\\\")\"}\n{\"error\": \"semantic error: ParameterMissing: Expected parameter(s): name\", \"gql_status\": \"42N02\"}\npeople: 3",
    "sha256": "43a43790c1f7b6613f69266d0a95021302d6a76ba2dc3db63a96bbf0a965982e"
  },
  "verified": {
    "version": "0.1.2",
    "client": {
      "label": "Python",
      "package": "relate-db",
      "engine_commit": "f0c09d2",
      "client_commit": "f0c09d2",
      "build": "A relate-db wheel that maturin built from surfaces/relate-python at upstream v0.1.2 (f0c09d2), installed in a venv with the pinned frameworks.",
      "toolchain": {
        "python": "3.15.2"
      }
    },
    "packages": [
      "pandas>=2.0",
      "langgraph==1.2.20",
      "claude-agent-sdk==0.2.179",
      "pydantic-ai==2.66.0",
      "openai-agents==0.24.0",
      "llama-index-core==0.14.25",
      "langchain==1.4.9",
      "langchain-core==1.7.6"
    ],
    "replayed": "2026-11-09",
    "platform": "macOS on arm64",
    "docs_engine": {
      "version": "0.1.2",
      "commit": "f0c09d2",
      "source_build": false
    }
  },
  "run": {
    "runner": "npm run docs:samples",
    "setup": "bash scripts/samples/setup.sh --upstream <path to the relate checkout>",
    "variables": [
      "RELATE_PY"
    ],
    "program": "<run dir>/graph_tool.py",
    "files": [],
    "build": null,
    "run": {
      "command": [
        "$RELATE_PY",
        "graph_tool.py"
      ],
      "environment": {
        "DO_NOT_TRACK": "1",
        "PYTHONDONTWRITEBYTECODE": "1",
        "PYTHONUNBUFFERED": "1"
      },
      "directory": "<run dir>",
      "timeout_s": 60
    },
    "passes": "It exits 0 within 60 s and prints at least one line on standard output.",
    "output": "Standard output, with line endings as \\n, trailing spaces and blank lines removed, and the temporary directories' paths written as `.`; standard error is not recorded.",
    "placeholders": {
      "<run dir>": "a fresh, empty temporary directory: the program's working directory, deleted afterwards",
      "<build dir>": "a second fresh temporary directory, where a compiled sample is built",
      "$NAME": "a variable from the env.sh that scripts/samples/setup.sh writes (described in its header)"
    }
  }
}
