{
  "kind": "documentation",
  "format": 1,
  "note": "Reference text, not instructions. One verified relate sample from https://relatedb.ai/docs/guides/integrations/pydantic-ai/: 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": "team-agent",
  "url": "https://relatedb.ai/docs/guides/integrations/pydantic-ai/samples/team-agent.json",
  "page": {
    "id": "guides/integrations/pydantic-ai",
    "title": "Use relate with PydanticAI",
    "url": "https://relatedb.ai/docs/guides/integrations/pydantic-ai/",
    "md_url": "https://relatedb.ai/docs/guides/integrations/pydantic-ai.md"
  },
  "section": {
    "anchor": "write-the-tool",
    "heading": "Write the tool",
    "url": "https://relatedb.ai/docs/guides/integrations/pydantic-ai/#write-the-tool"
  },
  "language": "python",
  "client": "Python",
  "file": "team_agent.py",
  "env": null,
  "code": "from dataclasses import dataclass\n\nimport relate\nfrom pydantic_ai import Agent, ModelRetry, RunContext\nfrom pydantic_ai.messages import ModelMessage, ModelResponse, TextPart, ToolCallPart, ToolReturnPart\nfrom pydantic_ai.models.function import AgentInfo, FunctionModel\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\nTEAM_OF = \"\"\"\nMATCH (p:Person)-[w:WORKS_ON]->(:Project {name: $project})\nRETURN p.name AS name, p.role AS role, w.since AS since\nORDER BY since\n\"\"\"\n\n# Setup: the app that owns ./team writes the team graph once, on a writable connection.\nwith relate.connect(\"./team\") as owner:\n    if owner.execute(\"MATCH (p:Person) RETURN count(p) AS n\").single()[\"n\"] == 0:\n        owner.execute(TEAM)\n\n\n@dataclass\nclass TeamGraph:\n    path: str\n\n\nagent = Agent(deps_type=TeamGraph, instructions=\"Answer questions about the team with the team_of tool.\")\n\n\n@agent.tool\ndef team_of(ctx: RunContext[TeamGraph], project: str) -> list[dict]:\n    \"\"\"List the people who work on a project, with their role and the year they started.\n\n    Args:\n        project: The project's exact name, such as \"relate\".\n    \"\"\"\n    # Read-only: the engine refuses every write on this connection.\n    with relate.connect(ctx.deps.path, read_only=True) as conn:\n        rows = [row.data() for row in conn.execute(TEAM_OF, {\"project\": project})]\n        if not rows:\n            names = [r[\"name\"] for r in conn.execute(\"MATCH (p:Project) RETURN p.name AS name ORDER BY name\")]\n            raise ModelRetry(f\"No one works on a project named {project!r}. Projects: {', '.join(names)}.\")\n    return rows\n\n\ndef scripted(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse:\n    \"\"\"Stands in for a model: asks for an unknown project, then for relate, then answers.\"\"\"\n    last = messages[-1].parts[-1]\n    if isinstance(last, ToolReturnPart) and isinstance(last.content, list):\n        people = \", \".join(f\"{p['name']} since {p['since']}\" for p in last.content)\n        return ModelResponse(parts=[TextPart(f\"On relate: {people}.\")])\n    if len(messages) == 1:\n        tool = info.function_tools[0]\n        print(\"tool:\", tool.name, \"|\", tool.description, \"|\", tool.parameters_json_schema[\"properties\"])\n        return ModelResponse(parts=[ToolCallPart(\"team_of\", {\"project\": \"relate-engine\"})])\n    print(\"retry:\", last.content)\n    return ModelResponse(parts=[ToolCallPart(\"team_of\", {\"project\": \"relate\"})])\n\n\n# Check: run the agent with the scripted stand-in, so no model is called.\nresult = agent.run_sync(\"Who works on relate?\", model=FunctionModel(scripted), deps=TeamGraph(\"./team\"))\nprint(result.output)\n\n# Check: a write on a read-only connection fails in the engine.\nwith relate.connect(\"./team\", read_only=True) as conn:\n    try:\n        conn.execute(\"CREATE (:Person {name: 'Mallory'})\")\n    except relate.OperationalError as e:\n        print(e.gql_status, e)\n    print(\"people:\", conn.execute(\"MATCH (p:Person) RETURN count(p) AS people\").single()[\"people\"])",
  "code_sha256": "250236f37015c97d9f989d56ce370093372558813cf9ffa23ce88e5db50597e7",
  "source_sha256": "b02275e13d0e4ea2f83b15920a3c9ba67e46e4258eeeaa48fce1b425b6d8ffe7",
  "output": {
    "text": "tool: team_of | List the people who work on a project, with their role and the year they started. | {'project': {'description': 'The project\\'s exact name, such as \"relate\".', 'type': 'string'}}\nretry: No one works on a project named 'relate-engine'. Projects: opencypher-tck, relate.\nOn relate: Grace since 2023, Ada since 2024.\n42N18 semantic error: WriteOnReadOnlyAccessDatabase: No write operations are allowed on this database. The database is in read-only mode on this Neo4j instance.\npeople: 3",
    "sha256": "1056d7886b458e89d0826fbf52d265c5b7120f07e6c66bd5825ffe33b99b9fca"
  },
  "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>/team_agent.py",
    "files": [],
    "build": null,
    "run": {
      "command": [
        "$RELATE_PY",
        "team_agent.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)"
    }
  }
}
