Skip to content

Add AI SDK recipes: health report, LangChain template and AI agent no…#27506

Open
prateekbaibhav wants to merge 6 commits intoopen-metadata:mainfrom
prateekbaibhav:main
Open

Add AI SDK recipes: health report, LangChain template and AI agent no…#27506
prateekbaibhav wants to merge 6 commits intoopen-metadata:mainfrom
prateekbaibhav:main

Conversation

@prateekbaibhav
Copy link
Copy Markdown

@prateekbaibhav prateekbaibhav commented Apr 18, 2026

Summary

This PR adds three Jupyter notebooks as AI SDK recipes for OpenMetadata.

Notebooks Added

  1. metadata_health_report.ipynb - Analyzes table documentation quality and generates health score
  2. langchain_openmetadata_template.ipynb - Reusable template connecting AI to OpenMetadata
  3. openmetadata_ai_agent.ipynb - AI agent that automatically decides how to search OpenMetadata

Related Issue

Closes #26646

Technologies Used

  • OpenMetadata Python SDK
  • Groq AI (LLaMA 3.3 70b)
  • Python, Pandas, Matplotlib
  • Jupyter Notebooks

Summary by Gitar

  • Documentation updates:
    • Expanded ingestion/examples/README.md with detailed problem statements, workflow explanations, and sample outputs for the AI recipes.
  • Setup and configuration:
    • Added requirements.txt to manage necessary environment dependencies.
  • Code improvements:
    • Implemented error handling across all notebooks.
    • Cleared sensitive data and execution outputs from notebooks for security.
    • Fixed a division-by-zero bug and corrected API key placeholder documentation.

This will update automatically on new commits.

…tebooks

Three Jupyter notebooks for OpenMetadata Hackathon 2026:
1) Metadata Health Report : analyzes table documentation quality
2) LangChain Template : connects AI to OpenMetadata
3) AI Agent : intelligent agent that autodecides how to search
Copilot AI review requested due to automatic review settings April 18, 2026 05:42
@prateekbaibhav prateekbaibhav requested a review from a team as a code owner April 18, 2026 05:42
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Comment thread ingestion/examples/metadata_health_report.ipynb Outdated
Comment on lines +147 to +158
" decision_prompt = f\"\"\"You are a data catalog agent. \n",
"You have these tools available:\n",
"1. get_tables - fetches list of tables\n",
"2. search_tables - searches tables by keyword\n",
"3. get_databases - fetches all databases\n",
"\n",
"User question: {user_question}\n",
"\n",
"Which tool should you use first? Reply with ONLY one of:\n",
"get_tables\n",
"search_tables: <keyword>\n",
"get_databases\"\"\"\n",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Security: Prompt injection via unsanitized user input and API data

In openmetadata_ai_agent.ipynb, user_question is interpolated directly into the LLM prompt (line 147 decision_prompt and line 183 final_prompt), and raw API response data is also injected into prompts (line 186 Data retrieved: {data}). A malicious table name or description in OpenMetadata could manipulate the LLM's behavior (indirect prompt injection). Similarly in langchain_openmetadata_template.ipynb, table names from the API are injected into the prompt at line 141.

For example recipes this may be acceptable, but consider adding a note about sanitization for production use, or at minimum escaping/truncating the data before prompt injection.

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

Comment on lines +250 to +253
"print(f\" ✅ Have Description : {has_description} ({round(has_description/total*100)}%)\")\n",
"print(f\" ❌ Missing Description : {missing_description} ({round(missing_description/total*100)}%)\")\n",
"print(f\" ✅ Have Owner : {has_owner} ({round(has_owner/total*100)}%)\")\n",
"print(f\" ❌ Missing Owner : {missing_owner} ({round(missing_owner/total*100)}%)\")\n",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: Division by zero when no tables are returned

In metadata_health_report.ipynb, the health score calculation uses total * 2 as a divisor (line 259/321) and the percentage calculations use total as a divisor (lines 250-253/312-315). If the API returns zero tables, total will be 0 and all these expressions will raise ZeroDivisionError. An example/recipe notebook should handle this gracefully since users may run it against an empty or misconfigured instance.

Suggested fix:

Add a guard before the summary block:

if total == 0:
    print("No tables found. Check your connection and token.")
else:
    # ... existing summary code ...

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

Comment on lines +236 to +250
"# Print a nice summary report\n",
"total = len(df)\n",
"has_description = (df[\"Has Description\"] == \"✅\").sum()\n",
"missing_description = (df[\"Has Description\"] == \"❌\").sum()\n",
"has_owner = (df[\"Has Owner\"] == \"✅\").sum()\n",
"missing_owner = (df[\"Has Owner\"] == \"❌\").sum()\n",
"total_columns = df[\"Total Columns\"].sum()\n",
"columns_missing_desc = df[\"Columns Missing Desc\"].sum()\n",
"\n",
"print(\"=\" * 50)\n",
"print(\" 📊 MY OPENMETADATA HEALTH REPORT\")\n",
"print(\" Built for OpenMetadata Hackathon 2026\")\n",
"print(\"=\" * 50)\n",
"print(f\" Total Tables Analyzed : {total}\")\n",
"print(f\" ✅ Have Description : {has_description} ({round(has_description/total*100)}%)\")\n",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Quality: Duplicate notebook cell: summary report appears twice

In metadata_health_report.ipynb, cells at lines 236-268 and 298-330 contain nearly identical code for printing the health report summary. The first version includes "Built for OpenMetadata Hackathon 2026" text while the second doesn't, but otherwise they are duplicates. This appears to be an editing artifact — one of them should be removed.

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

Comment thread ingestion/examples/openmetadata_ai_agent.ipynb
Comment thread ingestion/examples/README.md Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds three example Jupyter notebooks (plus a README) intended to serve as “AI SDK recipes” demonstrating OpenMetadata + AI workflows (health reporting, a LangChain-style template, and an AI agent).

Changes:

  • Added a metadata health report notebook that fetches tables and computes simple documentation/ownership coverage plus a chart export.
  • Added two AI-assisted notebooks: a Groq-backed Q&A template and a simple tool-choosing “AI agent” over OpenMetadata REST endpoints.
  • Added an ingestion/examples/README.md describing how to run the notebooks and install dependencies.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 16 comments.

File Description
ingestion/examples/openmetadata_ai_agent.ipynb New notebook: Groq-based agent that chooses between a few REST “tools” (tables/search/databases).
ingestion/examples/metadata_health_report.ipynb New notebook: basic metadata health scoring + CSV/chart export based on /api/v1/tables.
ingestion/examples/langchain_openmetadata_template.ipynb New notebook: Groq-based Q&A template over OpenMetadata REST endpoints (despite the “LangChain” name).
ingestion/examples/README.md New README describing the three notebooks and installation/setup steps.

Comment on lines +79 to +101
"def get_tables(limit=10):\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params={\"limit\": limit}\n",
" )\n",
" return response.json().get(\"data\", [])\n",
"\n",
"def get_databases():\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/databases\",\n",
" headers=HEADERS,\n",
" params={\"limit\": 20}\n",
" )\n",
" return response.json().get(\"data\", [])\n",
"\n",
"def search_assets(query):\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/search/query\",\n",
" headers=HEADERS,\n",
" params={\"q\": query, \"index\": \"table_search_index\", \"limit\": 5}\n",
" )\n",
" return response.json().get(\"hits\", {}).get(\"hits\", [])\n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This recipe makes HTTP calls to OpenMetadata but does not check for non-2xx responses before calling response.json(). If authentication fails or the server returns an error, this will raise confusing exceptions. Please add response.raise_for_status() (or explicit status checks) and surface a clear error message when the API call fails.

Suggested change
"def get_tables(limit=10):\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params={\"limit\": limit}\n",
" )\n",
" return response.json().get(\"data\", [])\n",
"\n",
"def get_databases():\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/databases\",\n",
" headers=HEADERS,\n",
" params={\"limit\": 20}\n",
" )\n",
" return response.json().get(\"data\", [])\n",
"\n",
"def search_assets(query):\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/search/query\",\n",
" headers=HEADERS,\n",
" params={\"q\": query, \"index\": \"table_search_index\", \"limit\": 5}\n",
" )\n",
" return response.json().get(\"hits\", {}).get(\"hits\", [])\n",
"def openmetadata_get(path, params=None):\n",
" url = f\"{BASE_URL}{path}\"\n",
" response = requests.get(url, headers=HEADERS, params=params)\n",
" try:\n",
" response.raise_for_status()\n",
" except requests.HTTPError as exc:\n",
" error_body = response.text.strip()\n",
" raise RuntimeError(\n",
" f\"OpenMetadata API request failed for {url} with status \"\n",
" f\"{response.status_code}: {error_body or 'No response body returned.'}\"\n",
" ) from exc\n",
"\n",
" try:\n",
" return response.json()\n",
" except ValueError as exc:\n",
" raise RuntimeError(\n",
" f\"OpenMetadata API request to {url} returned a non-JSON response.\"\n",
" ) from exc\n",
"\n",
"def get_tables(limit=10):\n",
" response_json = openmetadata_get(\n",
" \"/api/v1/tables\",\n",
" params={\"limit\": limit}\n",
" )\n",
" return response_json.get(\"data\", [])\n",
"\n",
"def get_databases():\n",
" response_json = openmetadata_get(\n",
" \"/api/v1/databases\",\n",
" params={\"limit\": 20}\n",
" )\n",
" return response_json.get(\"data\", [])\n",
"\n",
"def search_assets(query):\n",
" response_json = openmetadata_get(\n",
" \"/api/v1/search/query\",\n",
" params={\"q\": query, \"index\": \"table_search_index\", \"limit\": 5}\n",
" )\n",
" return response_json.get(\"hits\", {}).get(\"hits\", [])\n",

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +75
"cell_type": "code",
"execution_count": 11,
"id": "cfa44929-6991-432b-8455-071cf8a12fe0",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ Helper functions ready!\n"
]
}
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The committed cells include execution outputs and non-null execution_count values. This makes diffs noisy and can go stale quickly (especially for API-driven responses). Please clear outputs/reset execution counts before committing, or ensure the outputs are intentionally kept and match the current code.

Copilot uses AI. Check for mistakes.
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.9"
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notebook metadata indicates it was created with Python 3.13.9. OpenMetadata ingestion/examples are expected to run on supported Python versions (e.g., other repo notebooks use 3.11.x), so this kernel/version metadata is likely to mislead users and can break dependencies. Please re-save the notebook using a supported Python kernel (3.9–3.11) so language_info.version matches the supported runtime.

Suggested change
"version": "3.13.9"
"version": "3.11.9"

Copilot uses AI. Check for mistakes.
Comment on lines +299 to +330
"# Print a nice summary report\n",
"total = len(df)\n",
"has_description = (df[\"Has Description\"] == \"✅\").sum()\n",
"missing_description = (df[\"Has Description\"] == \"❌\").sum()\n",
"has_owner = (df[\"Has Owner\"] == \"✅\").sum()\n",
"missing_owner = (df[\"Has Owner\"] == \"❌\").sum()\n",
"total_columns = df[\"Total Columns\"].sum()\n",
"columns_missing_desc = df[\"Columns Missing Desc\"].sum()\n",
"\n",
"print(\"=\" * 50)\n",
"print(\" 📊 OPENMETADATA HEALTH REPORT\")\n",
"print(\"=\" * 50)\n",
"print(f\" Total Tables Analyzed : {total}\")\n",
"print(f\" ✅ Have Description : {has_description} ({round(has_description/total*100)}%)\")\n",
"print(f\" ❌ Missing Description : {missing_description} ({round(missing_description/total*100)}%)\")\n",
"print(f\" ✅ Have Owner : {has_owner} ({round(has_owner/total*100)}%)\")\n",
"print(f\" ❌ Missing Owner : {missing_owner} ({round(missing_owner/total*100)}%)\")\n",
"print(f\" Total Columns : {total_columns}\")\n",
"print(f\" Columns Missing Desc : {columns_missing_desc}\")\n",
"print(\"=\" * 50)\n",
"\n",
"# Health Score\n",
"score = round(((has_description + has_owner) / (total * 2)) * 100)\n",
"print(f\"\\n 🏥 Overall Health Score: {score}/100\")\n",
"if score >= 70:\n",
" print(\" Status: 🟢 HEALTHY\")\n",
"elif score >= 40:\n",
" print(\" Status: 🟡 NEEDS ATTENTION\")\n",
"else:\n",
" print(\" Status: 🔴 CRITICAL\")\n",
"print(\"=\" * 50)"
]
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The health report summary block is duplicated (same calculations and prints appear twice). This adds noise and increases maintenance cost. Please remove one of the duplicated summary cells and keep a single canonical summary section.

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +99
"def get_all_tables():\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params={\"limit\": 50}\n",
" )\n",
" data = response.json()\n",
" tables = data.get(\"data\", [])\n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_all_tables() hard-codes limit=50, so the report will only analyze the first page of tables and can significantly under-report health in larger catalogs. Please add pagination (iterate using the API paging mechanism) or make limit configurable and clearly document that this is a partial report.

Suggested change
"def get_all_tables():\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params={\"limit\": 50}\n",
" )\n",
" data = response.json()\n",
" tables = data.get(\"data\", [])\n",
"def get_all_tables(page_size=50):\n",
" tables = []\n",
" after = None\n",
"\n",
" while True:\n",
" params = {\"limit\": page_size}\n",
" if after:\n",
" params[\"after\"] = after\n",
"\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params=params\n",
" )\n",
" response.raise_for_status()\n",
"\n",
" data = response.json()\n",
" tables.extend(data.get(\"data\", []))\n",
"\n",
" after = data.get(\"paging\", {}).get(\"after\")\n",
" if not after:\n",
" break\n",
"\n",

Copilot uses AI. Check for mistakes.
Comment on lines +251 to +257
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.9"
}
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notebook metadata indicates it was created with Python 3.13.9. OpenMetadata ingestion/examples are expected to run on supported Python versions (e.g., repo notebooks under examples/python-sdk/... use 3.11.x), so this kernel/version metadata is likely to mislead users and can break dependencies. Please re-save the notebook using a supported Python kernel (3.9–3.11) so language_info.version matches the supported runtime.

Copilot uses AI. Check for mistakes.
Comment on lines +397 to +401
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABdAAAAJRCAYAAABFgJViAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQAA59VJREFUeJzs3Xd4FFX//vF7k5BGJ5QQpAvSm6BSFBQQKdYHEWwURR6xIfKAgFIVBAVRpCgCUak2EFB6E6T33qRDQknvye7O7w9+2S+bbEJCApPyfl3XXrozZ2bumV02u589e47FMAxDAAAAAAAAAADAiZvZAQAAAAAAAAAAyIkooAMAAAAAAAAA4AIFdAAAAAAAAAAAXKCADgAAAAAAAACACxTQAQAAAAAAAABwgQI6AAAAAAAAAAAuUEAHAAAAAAAAAMAFCugAAAAAAAAAALhAAR0AAAAAAAAAABcooAMAACDf2rBhgywWi+PWo0cPsyMhhR49ejg9Rhs2bLit/QQGBjrtZ8SIEdmaEwAAAHmTh9kBAAAA7pYTJ05o5syZWr9+vc6ePavw8HAVLlxY5cuX1yOPPKLu3bvr/vvvNztmtjt79qwqV66cavmUKVPUt29fl9t07txZv/32m9OyihUr6uzZs9mWa9KkSQoPD3fcz2sFzX379mnx4sWO+61atVKrVq3uagZXj71hGC7btmrVShs3bnTcnz17dq74QiEwMNDpedmvXz8VK1bsrufo0aOHfvjhB5frfH19VaZMGTVq1EgvvfSSnn322bucLucIDw/XpEmTHPcrVaqUK55nAAAg/6KADgAAcoRKlSrp3LlzGWq7adMmtWjRIsP7TkpK0oABAzRlyhTZbDandaGhoQoNDdX+/fs1efJkvfjii/ruu+9UsGDBTOXPjb799luXBfTg4GAtWbLkjh9/0qRJTo95Xiygjxw50mnZ3S6g5weBgYFOhf8ePXqYUkBPT2xsrM6cOaMzZ87ot99+U5cuXTR//ny5ueW/HwSHh4c7/bto2bIlBXQAAJCjUUAHAAA5xpgxY27ZM7NmzZqZ2qfdbtezzz6rP//8M9W6YsWKKSoqyqmoPm/ePJ08eVJ///23vL29M3Ws3ObAgQPavn27HnzwQaflM2fOVFJSkkmpgLyhYMGCKlSokOLj4xUREeG07ueff1b79u0pHAMAAOQC+a/LAwAAyLHKli2rGjVqpHvLrHHjxqUqnr/11lsKDg5WWFiYIiMjNWXKFKdi+c6dO9W/f/8sn09u8O233zrdt9vt+v77701KA+QdAwYMUHBwsMLDw3XixIlUX/79/PPPJiUDAABAZlBABwAAeVZUVJTGjx/vtKxHjx765ptvVKZMGUk3xibu27evpk2b5tRuxowZTsOLnD171mkCwlatWslms2nSpEmqV6+efHx8VKpUKXXt2lUnT55MM1NcXJymTp2qNm3aqHTp0vL09FTJkiXVpk0b/fDDD7Lb7am2SevYU6dOVaNGjeTr66vixYvrySef1IEDB255XW7+smDhwoVOvWNXrlzpGE/a19f3lvu6nXNq1aqVLBZLqiF7bj5Hi8XiyHHp0iWNGzdOnTt3Vu3ateXv7y9PT08VKlRI1atX1yuvvKJNmzalmc8wDM2YMUMNGzaUj4+PSpcurW7duqX7OCU7fvy4Ro8eraeeeko1atRQqVKlVKBAARUpUkS1a9dWnz59tH//fqdtkicm7dmzp9PykSNHpjlh6eLFi/Xee++pRYsWqly5sooUKSJPT0+VKlVKjzzyiMaPH6/IyMhb5r0b9u3bpzfeeEM1atRQoUKF5Ovrq+rVq+utt97S6dOnXW5zO9fxVpInF715+BZJqly5coYnHY2JidHQoUN17733ysvLSwEBAfrvf/+r69evZyrLrVSrVk0DBgxwWnbmzJk029/ONXY12eqRI0fUpUsXlS5dWj4+Pqpfv76mTJni8nUm2Y4dO9SrVy9Vr15dhQoVko+PjypVqqSuXbtq9erVLrdxNUHr1atX9eabb6pChQry8PBw5Es5Jv/GjRudtq1UqVKa2QAAAExhAAAA5AAVK1Y0Zs+efct2koxNmzZlaJ8LFy40JDluFovFOH/+vMu2drvduPfee53af/755471Z86ccVrXrFkzo0OHDk7Lkm+FCxc2tm/fnuoYR48eNapXr+5ym+Rbq1atjLCwMKftUh77gQceMNq1a5fmsY8ePZru9hUrVjRatmzpuP/NN9842j711FOO5T169Ei1XXac083HTu925swZwzAM45dffslQ+xEjRrh8bFOeR/KtUKFCxtixY52Wde/e3Wnbzz///JbH9fDwMGbOnOnYZv369RnKe/Oxateufcv2FStWNM6dO+fyHNOS8rFP7+1/ysfF1b/Hjz/+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upST044bN86pR7Uru3btUoUKFSTdneuYWe3atXManqR06dJO61O+HmQHDw8PzZw5U6+88kqqdVm9xim1bt3a6X6hQoXUpEkTrVmzxrHsyJEjatCggQ4dOuTUtk2bNi739+uvvzruJxffXWnfvv0tX38AAAByC3qgAwCAPCvlECQ390Z2JeX65N7UrrgapzdlwSi54JteT/a0XL9+Pc11roZWSTnO862GcJFuDFnz6KOPplreu3fvVOOTp5Td55SW5PGeM1I8l+RUAE65jauCXnpFvitXruiNN97IUNE35bEzY/r06RkunmflOMlSDpWTkaFOsvJ4363rmFkp/x3dzr+h9BQsWFClS5d2GvrEarWqe/fumjx5cqr22f1vKiuvUa62TbksvbyVKlVKcx0AAEBuQwEdAADkWTePwS3dmBgwrQkKDcPQihUrnJalHGLhZq4KVymXJU8imbInu4eHR6oJM1PeihcvnuaxU06aKCnVJIEZlXKoFg8PD/Xq1euW22X3OaVl69atCgoKctwPCAjQ2rVrFR0dLcMwFB8fn+a2KX+BkJHH7GbLly93+tVC7dq1tX37dsXFxckwDB07diwzp5KmlENhvP322zp//rxsNpsMw9CHH36YLcfJipSPd7FixW75eCc/T+/WdcyslP+ObvffUFoGDBigK1euKCIiQu+9955juWEY6t+/f6oe3Fm5xq5k5TXq2rVrqbZNuSy9X+gUKlQozXUAAAC5DUO4AACAPKtDhw4qVqyYwsPDJd0oXA0bNkyzZ89O1faHH37QqVOnHPc9PDz0/PPPp7nv06dP69y5c6pYsaJj2bp165za1KxZU9KNYlLlypUdQ54UKFBAJ0+eTFXgvZndbr/1CWaDZ599VqVLl9bVq1clSU8++aQCAgJuuV12nFPKXu42m82pt64kXb582el+165d9dhjjznu//PPP2keL/n6J9u3b59CQ0OdhnFJ+Zild+w+ffrogQceyNCxJdfnl5HjjBkzxuk63uo4d0PK8avffvttjR49Os32drvdcf5ZvY63ktHrbJaCBQtq0qRJ2rNnjzZt2iTpRk/0gQMHOk1UmpVr7Mq6deucJg6Njo5ONZ5+8r+ROnXqOC1fs2aNxo4d67Rs7dq1Tvfr1q2b5rHTk9MfLwAAgJTogQ4AAPKswoULa8CAAU7LAgMD9c477zgKxnFx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ucLDwzV9+nT98ccfatCggV544QWnscqT9erVSwUKFNBPP/2kX3/9VQUKFNDly5fl5+enzz77TCtWrNCUKVPk4eGhBx98UMePH8/262G1WlPdXPXI7tOnj/r166c2bdpo8eLFmjp1qg4fPqxmzZrpypUrjnb//vuvmjZtqmnTpmnVqlUaNmyYtm/frhYtWigpKSnNLFOnTlXz5s3l7++vrVu3Om43mzJlilavXq1JkyZp7ty5iomJUYcOHRQREZHueTZt2lRBQUF66aWXtHHjRsXFxaXZdubMmerQoYPsdrumT5+upUuX6t1339XFixcdbebNm6enn35aRYoU0fz58zVz5kyFhYWpVatW2rx5c6p9Pvfcc7r33nv1yy+/aPr06Zm6nsilDAAAAAAAACCXCQ4ONiQZXbt2TbfdCy+8YEgyrly5YhiGYfTv39/w8fExwsPDHW2OHDliSDImT57sWFajRg2jYcOGRlJSktP+OnXqZJQtW9aw2WyGYRjG7NmzDUnGq6++esvMVqvVSExMNKpVq2a8//77juVnzpwxJBmzZ892LEve75kzZ9LdZ3K79G4VK1Z0tN+6dashyZgwYYLTfi5cuGD4+PgYAwcOdHkcu91uJCUlGefOnTMkGX/88Ue6WTt27Oh03JTnWrduXcNqtTqW79ixw5BkzJ8/P93zjY+PN5555hnHubm7uxsNGzY0hg4daly9etXRLioqyihSpIjRokULw263u9yXzWYzAgICjLp16zoez+RtS5cubTRr1syxbPjw4YYkY9iwYU77uN3ridyDHugAAAAAAADIs4z/3wM7eWiPXr16KS4uTgsXLnS0mT17try8vPTiiy9Kkk6dOqVjx47ppZdekiSnHt0dOnRQUFBQqh7k//nPf1Id22q1asyYMapVq5Y8PT3l4eEhT09PnTx5UkePHs3W8/zxxx+1c+fOVLcWLVo4tVu2bJksFotefvllp/Py9/dX/fr1tWHDBkfbq1ev6r///a/Kly8vDw8PFShQQBUrVpSkLOfv2LGj3N3dHfeTe/6fO3cu3e28vLy0aNEiHTlyRF9++aW6du2qa9eu6dNPP1XNmjUdj8uWLVsUGRmpvn37pjkW/fHjx3X58mW98sorcnP7vzJpoUKF9J///Efbtm1TbGys0zYpH+fMXE/kTkwiCgAAAAAAgFynZMmS8vX11ZkzZ9Jtd/bsWfn6+qpEiRKSpNq1a6tJkyaaPXu23njjDdlsNs2ZM0dPP/20o03ysBsDBgzQgAEDXO435TjgZcuWTdWmf//+mjJligYNGqSWLVuqePHicnNz0+uvv57u0CO3o2bNmmrcuHGq5UWLFtWFCxcc969cuSLDMFSmTBmX+6lSpYokyW636/HHH9fly5f18ccfq27duipYsKDsdrseeuihLOf38/Nzuu/l5SVJGd5vzZo1VbNmTUk3viSZNGmS+vfvr48//lg///yzrl27JklpDu8j3RhPXXL92AUEBMhutyssLMxpotCUbTN6PZF7UUAHAAAAAABAruPu7q5HH31UK1as0MWLF10WSi9evKjdu3erffv2Tr2de/bsqb59++ro0aM6ffq0goKC1LNnT8f6kiVLSpIGDx6s5557zuXx77vvPqf7rno5z5kzR6+++qrGjBnjtPz69esqVqxYhs81O5UsWVIWi0WbNm1yFK1vlrzs0KFD2r9/vwIDA9W9e3fH+lOnTt21rBllsVj0/vvva9SoUTp06JAkqVSpUpLkNN55SslF/KCgoFTrLl++LDc3NxUvXjzVsW6W0euJ3IshXAAAAAAAAJArDR48WIZhqG/fvrLZbE7rbDab3nzzTRmGocGDBzut69atm7y9vRUYGKjAwECVK1dOjz/+uGP9fffdp2rVqmn//v1q3Lixy1vhwoVvmc9isaQqoP7555+6dOlSFs46azp16iTDMHTp0iWX51W3bl1J/1coTpn/22+/zdBxvLy8sr2XveS62C3dKHhHRkYqICBAktSsWTMVLVpU06dPdzmRqnTjcS5XrpzmzZvn1CYmJka//fabmjZt6tT73JWMXk/kXvRABwAAAAAAQK7UvHlzTZo0Sf369VOLFi309ttvq0KFCjp//rymTJmi7du3a9KkSWrWrJnTdsWKFdOzzz6rwMBAhYeHa8CAAU5jYEs3CsXt27dXu3bt1KNHD5UrV06hoaE6evSo9uzZo19++eWW+Tp16qTAwEDVqFFD9erV0+7du/X555+nO6zInda8eXO98cYb6tmzp3bt2qVHHnlEBQsWVFBQkDZv3qy6devqzTffVI0aNVS1alV9+OGHMgxDJUqU0NKlS7V69eoMHadu3br6/fffNW3aNN1///1yc3NzOcRMZr3xxhsKDw/Xf/7zH9WpU0fu7u46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kcaPH6/Q0NBM769Hjx6qVKlS9ge9CwIDA53es3h7e8vf31+PPvqoxo4dq6tXr5odMV0jRoyQxWK5rW0vX76sESNGaN++fdm63+yQkJCgb775Ri1atFDx4sXl6empcuXKqUuXLtq4caNpuQAAAJBzeJgdAMiIrVu3Ot0fPXq01q9fr3Xr1jktr1Wr1t2MdVuqVKmiuXPnSpJiYmJ05swZLV68WM8//7wefvhhLV26VEWLFjU5pWuLFi1SkSJFbmvbv/76S1OmTHFZRM/KfrNq2bJl6tq1q0qWLKm3335bDRs2lMVi0cGDBzVr1iz9+eef2rt3rynZACA3mzFjhvr27av77rtP//vf/1SrVi0lJSVp165dmj59urZu3apFixaZHfOumz17tmrUqKGkpCRdvXpVmzdv1rhx4/TFF19o4cKFatOmjdkRXXr99df1xBNP3Na2ly9f1siRI1WpUiU1aNAg2/abVdevX9cTTzyhAwcOqFevXvrf//6nEiVK6NKlS/rjjz/UunVr7d69W/Xr1zclHwAAAHIGCujIFR566CGn+6VKlZKbm1uq5bmBj49Pqtyvv/66Zs+erV69eumNN97QwoULTUrnWlxcnHx8fNSwYcM7sv87td9bOXPmjLp27arq1atr/fr1Tl9cPPbYY3r33XdzbHEnNjZWvr6+ZscAAJe2bt2qN998U23bttXixYvl5eXlWNe2bVt98MEHWrFihYkJzVOnTh01btzYcf8///mP3n//fbVo0ULPPfecTp48qTJlypiY0Fny35t77rlH99xzT7bv/07tNyNeffVV7d+/XytXrtRjjz3mtK5r167q37+/ihcvbkq29NhsNlmtVqd/VwAAALhzGMIFecaUKVP0yCOPqHTp0ipYsKDq1q2r8ePHKykpyWX7TZs26aGHHpKPj4/KlSunjz/+WDab7ZbHCQ4OVp8+fXTPPffI09NTlStX1siRI2W1WrOUv2fPnurQoYN++eUXnTt3zrHcMAxNnTpVDRo0kI+Pj4oXL67OnTvr9OnTTtvv3btXnTp1UunSpeXl5aWAgAB17NhRFy9edLSx2+2aPHmyY1/FihXTQw89pCVLljjaVKpUSZ06ddLvv/+uhg0bytvbWyNHjnSsu3molQ0bNshisWjOnDnq37+//P395ePjo5YtWzr12u7Ro4emTJkiyXk4nrNnz7rcrySdP39eL7/8suN8atasqQkTJjgNc3P27FlZLBZ98cUXmjhxoipXrqxChQqpadOm2rZt2y2v+cSJExUTE6OpU6e67PVvsVj03HPPOS2bNWuW6tevL29vb5UoUULPPvusjh496lg/adIkWSwWnTp1KtX+Bg0aJE9PT12/ft2xbM2aNWrdurWKFCkiX19fNW/eXGvXrnXaLvnn7Xv27FHnzp1VvHhxVa1aVZK0a9cude3aVZUqVZKPj48qVaqkbt26OT2Hkm3evFlNmzaVt7e34zn//fffOz0WyRYuXKimTZuqYMGCKlSokNq1a0dPfAAZNmbMGFksFn333Xcui3yenp566qmnHPftdrvGjx+vGjVqyMvLS6VLl9arr77q9DfMleS/A4GBganWpRyGLfm19MCBA3r++edVtGhRlShRQv3795fVatXx48f1xBNPqHDhwqpUqZLGjx/vtL/kv3nz58/X0KFDFRAQoCJFiqhNmzY6fvx45i5QChUqVNCECRMUFRWlb7/91mndrl279NRTT6lEiRLy9vZWw4YN9fPPPzu1iY2N1YABAxxD5ZQoUUKNGzfW/Pnzndpt375dTz75pPz8/OTt7a2qVauqX79+qa6Rq783roZaSX7PsGjRItWrV0/e3t6qUqWKvv76a6fr1qRJE0k33uskvwdIfmxc7Tejz4fkYfl27typhx9+WL6+vqpSpYo+++yzWw6Lt3v3bi1fvlyvvfZaquJ5siZNmqhChQqO+4cOHdLTTz+t4sWLy9vbWw0aNNAPP/zgWH/t2jV5enrq448/TrWvY8eOyWKxOF2bjLynTH6Ojx8/Xp988okqV64sLy8vrV+/XvHx8frggw/UoEEDx/O5adOm+uOPP1IdPzw8XK+99ppKlCihQoUKqWPHjjp9+rTL4QpPnjypF1980ek9WPL7OAAAgPyIAjryjH///VcvvviifvrpJy1btkyvvfaaPv/8c/Xp0ydV2+DgYHXt2lUvvfSS/vjjD3Xu3FmffPKJ3nvvvXSPERwcrAceeEArV67UsGHDHB+8xo4dq969e2f5HJ566ikZhqFNmzY5lvXp00f9+vVTmzZttHjxYk2dOlWHDx9Ws2bNdOXKFUk3hoJp27atrly5oilTpmj16tWaNGmSKlSooKioKMe+evTooffee09NmjTRwoULtWDBAj311FOpiqd79uzR//73P7377rtasWKF/vOf/6Sbe8iQITp9+rS+//57ff/997p8+bJatWrlKPJ//PHH6ty5s6QbvRKTb2XLlnW5v2vXrqlZs2ZatWqVRo8erSVLlqhNmzYaMGCA3n777VTtbz7nuXPnKiYmRh06dFBERES6uVetWqUyZcpk+JcMY8eO1WuvvabatWvr999/11dffaUDBw6oadOmOnnypCTp5ZdflqenZ6pijs1m05w5c/Tkk0+qZMmSkqQ5c+bo8ccfV5EiRfTDDz/o559/VokSJdSuXbtURXRJeu6553Tvvffql19+0fTp0yXd+GB93333adKkSVq5cqXGjRunoKAgNWnSxKlQf+DAAbVt21axsbH64YcfNH36dO3Zs0effvppquOMGTNG3bp1U61atfTzzz/rp59+UlRUlB5++GEdOXIkQ9cKQP5ls9m0bt063X///SpfvnyGtnnzzTc1aNAgtW3bVkuWLNHo0aO1YsUKNWvWzOm1LDt06dJF9evX12+//abevXvryy+/1Pvvv69nnnlGHTt21KJFi/TYY49p0KBB+v3331NtP2TIEJ07d07ff/+9vvvuO508eVJPPvlkhr6ET0+HDh3k7u6uv//+27Fs/fr1at68ucLDwzV9+nT98ccfatCggV544QWnvzP9+/fXtGnTHH+3f/rpJz3//PMKCQlxtFm5cqUefvhhnT9/XhMnTtTy5cv10UcfOd5L3MzV35u07Nu3T/369dP777+vRYsWqVmzZnrvvff0xRdfSJIaNWqk2bNnS5I++ugjx3uA119/Pc19Zub5EBwcrJdeekkvv/yylixZovbt22vw4MGaM2dOurlXrVolSXrmmWfSbZfs+PHjatasmQ4fPqyvv/5av//+u2rVqqUePXo4vmwpVaqUOnXqpB9++CFVAX/27Nny9PTUSy+95MidmfeUX3/9tdatW6cvvvhCy5cvV40aNZSQkKDQ0FANGDBAixcv1vz58x2/ZPjxxx8d29rtdj355JOaN2+eBg0apEWLFunBBx90OXTOkSNH1KRJEx06dEgTJkzQsmXL1LFjR7377ruODhUAAAD5DUO4IM+YOHGi4//tdrsefvhh+fn5qWfPnpowYYLTT3BDQkL0xx9/OHq/Pf7444qLi9O0adM0cOBAp95GNxsxYoTCwsJ0+PBhR5vWrVvLx8dHAwYMcIzxersq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yy+/OLVr166dPDw89O+//6aZCwBuZfDgwTIMQ71791ZiYmKq9UlJSVq6dKkk6bHHHpOkVK+vO3fu1NGjR1O9vt6sTJky8vb21oEDB5yW//HHH1k9hbvq/PnzGjBggIoWLeqY/Py+++5TtWrVtH///jRfjwsXLpxqX2XKlFGPHj3UrVs3HT9+XLGxsapevbqqVq2qWbNmpSquZtXhw4e1f/9+p2Xz5s1T4cKF1ahRI0mZew+QledDZjRq1Ejt27fXzJkzUw0Nl2zXrl2OsdJbt26tdevWOY1RL914b+Lr6+v0ZXjNmjX14IMPavbs2S6/RJey5z2lxWKRp6enU/E8ODg41fO/ZcuWkpRqDpMFCxY43ff19dWjjz6qvXv3ql69ei5z3W7nCAAAgNyMHujIE5InQurWrZsGDhyo+Ph4TZs2TWFhYS7b+/n56c0339T58+dVvXp1/fXXX5oxY4befPPNNCcQlaRRo0Zp9erVatasmd59913dd999io+P19mzZ/XXX39p+vTpt+xpFxcX5xg/Mi4uTqdPn9bixYu1bNkytWzZUtOnT3e0bd68ud544w317NlTu3bt0iOPPKKCBQsqKChImzdvVt26dfXmm29q2bJlmjp1qp555hlVqVJFhmHo999/V3h4uGMCq4cfflivvPKKPvnkE125ckWdOnWSl5eX9u7dK19fX73zzjuZvewOV69e1bPPPqvevXsrIiJCw4cPl7e3t9PEVMnF/nHjxql9+/Zyd3dXvXr1XBaJ33//ff3444/q2LGjRo0apYoVK+rPP//U1KlT9eabb2ZqfPb0VK5c2dE7rEGDBnr77bfVsGFDSdKRI0c0a9YsGYahZ599VsWKFdPHH3/smLStW7duCgkJ0ciRI+Xt7a3hw4c77btGjRpq2rSpxo4dqwsXLui7775zWl+oUCFNnjxZ3bt3V2hoqDp37qzSpUvr2rVr2r9/v65du3bLLzuKFCmiRx55RJ9//rlKliypSpUqaePGjZo5c6aKFSvm1Hbo0KFaunSpWrduraFDh8rHx0fTp093jLOePNlppUqVNGrUKA0dOlSnT5/WE088oeLFi+vKlSvasWOHo5cjAKSnadOmmjZtmvr27av7779fb775pmrXrq2kpCTt3btX3333nerUqaMnn3xS9913n9544w1NnjxZbm5uat++vc6ePauPP/5Y5cuXd5oYM6XkeUJmzZqlqlWrqn79+tqxY4fTZM85zaFDhxzjSl+9elWbNm3S7Nmz5e7urkWLFjl6i0vSt99+q/bt26tdu3bq0aOHypUrp9DQUB09elR79uxxfAn64IMPqlOnTqpXr56KFy+uo0eP6qefflLTpk3l6+srSZoyZYqefPJJPfTQQ3r//fdVoUIFnT9/XitXrtTcuXNv+3wCAgL01FNPacSIESpbtqzmzJmj1atXa9y4cY5jV61aVT4+Ppo7d65q1qypQoUKKSAgwGWROCvPh8z68ccf9cQTT6h9+/bq1auX2rdvr+LFiysoKEhLly7V/PnztXv3blWoUEHDhw93jFs+bNgwlShRQnPnztWff/6p8ePHq2jRok777tWrl/r06aPLly+rWbNmjl8LJMuO95SdOnXS77//rr59+6pz5866cOGCRo8erbJlyzqG75FuTBjfvHlzffDBB4qMjNT999+vrVu36scff5T0f+8BJOmrr75SixYt9PDDD+vNN99UpUqVFBUVpVOnTmnp0qVpftkAAACQl1FAR55Qo0YN/fbbb/roo4/03HPPyc/PTy+++KL69+/vNClYMn9/f02ZMkUDBgzQwYMHVaJECQ0ZMuSWhcGyZctq165dGj16tD7//HNdvHhRhQsXVuXKlR2Fxls5ffq0mjZtKunGT67LlCmjRo0a6ZdfftFzzz3n9CFGuvHh+aGHHtK3336rqVOnym63KyAgQM2bN3dMmlWtWjUVK1ZM48eP1+XLl+Xp6an77rtPgYGB6t69u2NfgYGBatSokWbOnKnAwED5+PioVq1aGjJkyC1zp2fMmDHauXOnevbsqcjISD3wwANasGCBqlat6mjz4osv6p9//tHUqVM1atQoGYahM2fOqFKlSqn2V6pUKW3ZskWDBw/W4MGDFRkZqSpVqmj8+PHq379/lrKm1KlTJx08eFATJkzQ9OnTdeHCBbm5uTke05u/WBg8eLBKly6tr7/+WgsXLpSPj49atWqlMWPGqFq1aqn23bNnT73xxhvy8fHRCy+8kGr9yy+/rAoVKmj8+PHq06ePoqKiVLp0aTVo0CDV5GlpmTdvnt577z0NHDhQVqtVzZs31+rVq9WxY0endvXr19fq1as1YMAAvfrqqypevLheeeUVtWzZUoMGDXL64D948GDVqlVLX331lebPn6+EhAT5+/urSZMm+u9//5vBKwsgv+vdu7ceeOABffnllxo3bpyCg4NVoEABVa9eXS+++KLefvttR9tp06apatWqmjlzpqZMmaKiRYvqiSee0NixY2/Z43XChAmSpPHjxys6OlqPPfaYli1b5vLvS06Q3BPZ09NTxYoVU82aNTVo0CC9/vrrTsVzSXr00Ue1Y8cOffrpp+rXr5/CwsLk5+enWrVqOU0I+dhjj2nJkiX68ssvFRsbq3LlyunVV1/V0KFDHW3atWunv//+W6NGjdK7776r+Ph43XPPPakmRc2sBg0aqGfPnho+fLhOnjypgIAATZw40anQ7evrq1mzZmnkyJF6/PHHlZSUpOHDh2vEiBEu95mV50NmlCxZUps3b9aMGTM0f/58zZs3T7GxsSpdurQeeughLVmyxDFB6n333actW7ZoyJAheuuttxQXF6eaNWtq9uzZLv9md+3aVf369dPFixdTfckuZc97yp49e+rq1auaPn26Zs2apSpVqujDDz/UxYsXnd7Turm5aenSpfrggw/02WefKTExUc2bN9ecOXP00EMPOX3pXqtWLe3Zs0ejR4/WRx99pKtXr6pYsWKqVq2aYxx0AACA/MZi3DzuAgBkwoYNG/Too4/ql19+UefOnc2Og9vw+OOP6+zZszpx4oTZUQAAuUylSpVUp04dLVu2zOwouA3z5s3TSy+9pH/++UfNmjUzOw6Q40VGRqpo0aKKiIhQkSJFbns/IRGR2ZgKAPIvv6K3/1osZe51nR7oAJBP9O/fXw0bNlT58uUVGhqquXPnavXq1Zo5c6bZ0QAAwB00f/58Xbp0SXXr1pWbm5u2bdumzz//XI888gjFcwAAgFuggA4A+YTNZtOwYcMUHBwsi8WiWrVq6aefftLLL79sdjQAAHAHFS5cWAsWLNAnn3yimJgYlS1bVj169NAnn3xidjQAAIAcjyFcAAAAAAAA0sEQLgCQs9zNIVzc0l0LAAAAAAAAAEA+RQEdAAAAAAAAAAAXKKADAAAAAAAAAOACBXQAAAAAAAAAAFyggA4AAAAAAAAAgAsU0AEAAAAAAAAAcIECOgAAAAAAAAAALlBABwAAAAAAAADABQroAAAAAAAAAAC4QAEdAAAAAAAAAAAXKKADAAAAAAAAAOACBXQAAAAAAAAAAFyggA4AAAAAAAAAgAsU0AEAAAAAAAAAcIECOgAAAAAAAAAALlBABwAAAAAAAADABQroAAAAAAAAAAC4QAEdAAAAAAAAAAAXKKADAAAAAAAAAOACBXQAAAAAAAAAAFyggA4AAAAAAAAAgAsU0AEAAAAAAAAAcIECOgAAAAAAAAAALlBABwAAAAAAAADABQroAAAAAAAAAAC4QAEdAAAAAAAAAAAXKKADAAAgXxgxYoQaNGiQ5f1s2LBBFotF4eHhWd4XAAAAgJyNAjoAAEAe06NHDz3zzDOplt/pwu/Zs2dlsVgct8KFC6t27dp66623dPLkyTtyzMwYMGCA1q5dm6ltWrVqpX79+jkta9asmYKCglS0aNFsTAcAAAAgJ6KADgAAgGy1Zs0aBQUFaf/+/RozZoyOHj2q+vXrZ7p4nV0Mw5DValWhQoXk5+eX5f15enrK399fFoslG9IBAAAAyMkooAMAAORTISEh6tatm+655x75+vqqbt26mj9/vlObX3/9VXXr1pWPj4/8/PzUpk0bxcTEpLtfPz8/+fv7q0qVKnr66ae1Zs0aPfjgg3rttddks9kc7ZYuXar7779f3t7eqlKlikaOHCmr1epYP2LECFWoUEFeXl4KCAjQu+++61iXkJCggQMHqnz58vLy8lK1atU0c+ZMSf/X037lypVq3LixvLy8tGnTplRDuCT31B85cqRKly6tIkWKqE+fPkpMTHSs37hxo7766itHr/qzZ8+67Mn/22+/qXbt2vLy8lKlSpU0YcIEp2tSqVIljRkzRr169VLhwoVVoUIFfffddxl7oAAAAACYhgI6AABAPhUfH6/7779fy5Yt06FDh/TGG2/olVde0fbt2yVJQUFB6tatm3r16qWjR49qw4YNeu6552QYRqaO4+bmpvfee0/nzp3T7t27JUkrV67Uyy+/rHfffVdHjhzRt99+q8DAQH366aeSbhTuv/zyS3377bc6efKkFi9erLp16zr2+eqrr2rBggX6+uuvdfToUU2fPl2FChVyOu7AgQM1duxYHT16VPXq1XOZbe3atTp69KjWr1+v+fPna9GiRRo5cqQk6auvvlLTpk3Vu3dvBQUFKSgoSOXLl0+1j927d6tLly7q2rWrDh48qBEjRujjjz9WYGCgU7sJEyaocePG2rt3r/r27as333xTx44dy9S1BAAAAHB3eZgdAAAAANlv2bJlqQrKN/f+lqRy5cppwIABjvvvvPOOVqxYoV9++UUPPviggoKCZLVa9dxzz6lixYqS5FTEzowaNWpIujFO+gMPPKBPP/1UH374obp37y5JqlKlikaPHq2BAwdq+PDhOn/+vPz9/dWmTRsVKFBAFSpU0AMPPCBJOnHihH7++WetXr1abdq0cWyf0qhRo9S2bdt0c3l6emrWrFny9fVV7dq1NWrUKP3vf//T6NGjVbRoUXl6esrX11f+/v5p7mPixIlq3bq1Pv74Y0lS9erVdeTIEX3++efq0aOHo12HDh3Ut29fSdKgQYP05ZdfasOGDY5rAwAAACDnoQc6AABAHvToo49q3759Trfvv//eqY3NZtOnn36qevXqyc/PT4UKFdKqVat0/vx5SVL9+vXVunVr1a1bV88//7xmzJihsLCw28qT3Gs9edzw3bt3a9SoUSpUqJDjltzTOzY2Vs8//7zi4uJUpUoV9e7dW4sWLXIM77Jv3z65u7urZcuW6R6zcePGt8xVv359+fr6Ou43bdpU0dHRunDhQobP7ejRo2revLnTsubNm+vkyZNOX1rc3AveYrHI399fV69ezfBxAAAAANx9FNABAADyoIIFC+ree+91upUrV86pzYQJE/Tll19q4MCBWrdunfbt26d27do5xgB3d3fX6tWrtXz5ctWqVUuTJ0/WfffdpzNnzmQ6z9GjRyVJlStXliTZ7XaNHDnSqcB/8OBBnTx5Ut7e3ipfvryOHz+uKVOmyMfHR3379tUjjzyipKQk+fj4ZPga3K7MTBBqGEaq9q6GuSlQoECqY9jt9tsLCAAAAOCuoIAOAACQT23atElPP/20Xn75ZdWvX19VqlTRyZMnndpYLBY1b95cI0eO1N69e+Xp6alFixZl6jh2u11ff/21KleurIYNG0qSGjVqpOPHj6cq8t97771yc7vxFtXHx0dPPfWUvv76a23YsEFbt27VwYMHVbduXdntdm3cuDHL12D//v2Ki4tz3N+2bZsKFSqke+65R9KNIV5SDn2TUq1atbR582anZVu2bFH16tXl7u6e5YwAAAAAzMMY6AAAAPnUvffeq99++01btmxR8eLFNXHiRAUHB6tmzZqSpO3bt2vt2rV6/PHHVbp0aW3fvl3Xrl1zrE9LSEiIgoODFRsbq0OHDmnSpEnasWOH/vzzT0dBediwYerUqZPKly+v559/Xm5ubjpw4IAO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uum2227TwIEDVVRUdEYyHKmwsFDS4ZM7lseM6fL6cwEAAPCHAh0AAABAtdWyZUvVrl1bs2bN8m2bNWuWEhMTfScc/NORo0Kef/55paamyuVyKTY2VhdddJHvug8++EBNmzaV2+1WVFSUevbsqQMHDkg6eoRL165ddeutt2rs2LGKjIxUXFycJkyYUOq+N23apI4dO8rlcqlx48b6+OOPT2oEitPpVFxcnBISEtSyZUvdc889mjt3rhYsWOBbWS8dXhV//fXXKyYmRqGhoerevbvWrVvnu37dunXq1q2bQkJCFBoaqlatWmnVqlW+67/88kt16dJFHo9HERER6tOnjzIzM32Pb9SoURozZoyio6PVq1cvSaVHuGzbtk2GYWjmzJlq3769XC6X0tLStHTpUt/13bp1kyRFRETIMAwNGzbM759LZmamhg4dqoiICHk8HvXr109btmzxXT99+nSFh4frv//9rxo1aqTg4GDfGw0AAABHokAHAAAAUK1dc801euONN3yXX3/9dQ0fPvy4t1m1apVuvfVWTZo0SZs3b9bChQvVuXNnSdKuXbt02WWXafjw4dq4caOWLl2qwYMH63jTM2fMmKGgoCCtWLFC06ZN06RJk7R48WJJUklJiQYNGiSPx6MVK1bo5Zdf1r333lvmx9u9e3c1b97c96aB1+vVgAEDlJ6ervnz52v16tVq2bKlevTooX379kmSrrjiCtWqVUsrV67U6tWrNW7cONntdknS2rVr1aNHD6Wlpemrr77SsmXLdO6556q4uLjU47PZbPryyy/10ksvHTPbXXfdpTvuuENr1qxR+/btdd555ykjI0OJiYn68MMPJUmbN2/Wrl279NRTT/k9xrBhw7Rq1SrNmzdPX331lbxer/r3769Dhw759snLy9Ojjz6qN998U59//rm2b9+uO++8s8zPKQAAqLpsZgcAAAAAADNdddVVGj9+vG8V9JdffqmZM2f6Vj/7s337dgUFBWngwIEKCQlRUlKSb8X6rl27VFRUpMGDByspKUmS1LRp0+NmaNasmR588EFJUmpqqp599lktWbJEvXr10qJFi/TTTz9p6dKliouLkyRNnjzZt5K7LBo2bKj169dLkj799FNt2LBBu3fv9o1UefTRRzVnzhx98MEHuv7667V9+3bdddddatiwoS/jn6ZNm6bWrVvr+eef921L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Vd6JVp7/iZOIAgAAAACAKsvhcKhVq1ZavHhxqe2LFy9W+/btTUoFAKgsWIEOAAAAAACqtDFjxuiqq65S69at1a5dO7388svavn27brzxRrOjAQACHAU6AAAAAACo0i655BJlZGRo0qRJ2rVrl5o0aaL58+crKSnJ7GhAQHE6nXrwwQePGmEEVGeG1+v1mh0CAAAAAAAAAIBAwwx0AAAAAAAAAAD8oEAHAAAAAAAAAMAPCnQAAAAAAAAAAPygQAcAAAAAAACqiKVLl8owDO3fv/+4+yUnJ+vJJ588I5mAyowCHQAAAAAAAKhAw4YN06BBg47afrJl9+mYPn26wsPDy+VYu3fv1g033KDatWvL6XQqLi5Offr00VdffVUuxwcCkc3sAAAAAAAAAAAC34UXXqhDhw5pxowZqlu3rn7//XctWbJE+/btq7D7LCwslMPhqLDjAyfCCnQAAAAAAAAgQCxfvlydO3eW2+1WYmKibr31Vh04cMB3/VtvvaXWrVsrJCREcXFxuvzyy7V7926/x1q6dKmuueYaZWVlyTAMGYahCRMm+K7Py8vT8OHDFRISotq1a+vll18+Zq79+/dr2bJlmjp1qrp166akpCS1adNG48eP14ABA0rtd/311ys2NlYul0tNmjTRRx995Lv+ww8/VFpampxOp5KTk/XYY4+Vup/k5GT94x//0LBhwxQWFqbrrrvupJ4XoKJQoAMAAAAAAAABYMOGDerTp48GDx6s9evX67333tOyZcs0atQo3z6FhYV66KGHtG7dOs2ZM0dbt27VsGHD/B6vffv2evLJJxUaGqpdu3Zp165duvPOO33XP/bYY2rdurXWrFmjkSNH6qabbtKmTZv8His4OFjBwcGaM2eOCgoK/O5TUlKifv36afny5Xrrrbf0/fff65FHHpHVapUkrV69WhdffLEuvfRSbdiwQRMmTND999+v6dOnlzrOP//5TzVp0kSrV6/W/ffff1LPC1BRDK/X6zU7BAAAAAAAAFBVDRs2TG+99ZZcLlep7cXFxcrPz1dmZqbCw8M1dOhQud1uvfTSS759li1bpi5duujAgQNH3V6SVq5cqTZt2ignJ0fBwcFaunSpunXr5jvm9OnTNXr06KPmrCcnJ6tTp0568803JUler1dxcXGaOHGibrzxRr+P48MPP9R1112ngwcPqmXLlurSpYsuvfRSNWvWTJK0aNEi9evXTxs3blT9+vWPuv0VV1yhPXv2aNGiRb5tY8eO1X/+8x999913vlwtWrTQ7NmzffuU5XkBygsr0AEAAAAAAIAK1q1bN61du7bU16uvvlpqn9WrV2v69Om+1d7BwcHq06ePSkpKtHXrVknSmjVrdP755yspKUkhISHq2rWrJGn79u2nnOnP4luSDMNQXFzcMcfBSIdnoP/222+aN2+e+vTpo6VLl6ply5a+FeRr165VrVq1/JbnkrRx40Z16NCh1LYOHTpoy5YtKi4u9m1r3bp1qX1O5nkBKgonEQUAAAAAAAAqWFBQkFJSUkpt27lzZ6nLJSUluuGGG3TrrbcedfvatWvrwIED6t27t3r37q233npLNWrU0Pbt29WnTx8VFhaecia73V7qsmEYKikpOe5tXC6XevXqpV69eumBBx7QiBEj9OCDD2rYsGFyu93Hva3X65VhGEdtO1JQUFCpyyd6XoCKRIEOAAAAAAAABICWLVvqu+++O6po/9OGDRu0d+9ePfLII0pMTJQkrVq16rjHdDgcpVZ3l7fGjRtrzpw5kg6vaN+5c6d++OEHv6vQGzdurGXLlpXatnz5ctWvX983J92fEz0vQEVihAsAAAAAAAAQAO6++2599dVXuvnmm7V27Vpt2bJF8+bN0y233CLp8Gprh8OhZ555Rj///LPmzZunhx566LjHTE5OVm5urpYsWaK9e/cqLy+vTNkyMjLUvXt3vfXWW1q/fr22bt2qf/3rX5o2bZrOP/98SVKXLl3UuXNnXXjhhVq8eLG2bt2qBQsWaOHChZKkO+64Q0uWLNFDDz2kH374QTNmzNCzzz5b6sSmZXlegIpEgQ4AAAAAAAAEgGbNmumzzz7Tli1b1KlTJ7Vo0UL333+/4uPjJUk1atTQ9OnT9a9//UuNGzfWI488okcfffS4x2zfvr1uvPFGXXLJJapRo4amTZtWpmzBwcFq27atnnjiCXXu3FlNmjTR/fffr+uuu07PPvusb78PP/xQZ599ti677DI1btxYY8eO9a2Ab9mypd5//33NnDlTTZo00QMPPKBJkyZp2LBhp/W8ABXJ8PobNAQAAAAAAAAAQDXHCnQAAAAAAAAAAPygQAcAAAAAAAAAwA8KdAAAAAAAAAAA/KBABwAAAAAAAADADwp0AAAAAAAAAAD8oEAHAAAAAAAAAMAPCnQAAAAAAAAAAPygQAcAAAAAAAAAwA8KdAAAAAAAAAAA/KBABwAAAAAAAADADwp0AAAAAAAAAAD8oEAHAAAAAAAAAMCP/wdeaCJODfHB+gAAAABJRU5ErkJggg==",
"text/plain": [
"<Figure size 1500x600 with 3 Axes>"
]
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This notebook commits a large embedded PNG output ("image/png": "iVBOR..."). This bloats the repository and makes diffs noisy. Please clear cell outputs before committing (or keep only minimal text outputs) and rely on the saved metadata_health_chart.png artifact (or regenerate locally) instead of embedding base64 image data in git.

Copilot uses AI. Check for mistakes.
Comment on lines +233 to +250
"\n",
"\n",
"❓ User: Find tables related to orders\n",
"============================================================\n",
"🧠 Agent thinking about: Find tables related to orders\n",
"--------------------------------------------------\n",
"🔧 Agent decided to use: search_tables: orders\n",
"📦 Data fetched: ['raw_orders', 'fact_orders', 'fact_orders', 'orders', 'orders', 'orders', 'orders', 'orders', 'orders', 'table_soldier_answer_8ad293a8']\n",
"--------------------------------------------------\n",
"🤖 Agent answer: I've searched for tables related to \"orders\" in our data catalog. Here are the results:\n",
"\n",
"We have found several tables that may be relevant to your query:\n",
"1. **raw_orders**: This table likely contains raw, unprocessed data related to orders.\n",
"2. **fact_orders**: This table appears to be a fact table, which is a type of table used in data warehousing to store measurable data, such as order quantities, amounts, or dates. There are multiple instances of this table in our search results.\n",
"3. **orders**: This table is directly named \"orders\" and may contain a wide range of data related to orders. There are multiple instances of this table in our search results, which could indicate different versions, updates, or copies of the same data.\n",
"4. **table_soldier_answer_8ad293a8**: This table seems unrelated to orders based on its name. It's possible that this result is a false positive or that the table contains some data related to orders that isn't immediately apparent from its name.\n",
"\n",
"To help you further, I can try to:\n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This notebook includes committed execution outputs (e.g., stdout showing API results). In openmetadata_ai_agent.ipynb the captured demo output does not match the test_questions list in the source cell, suggesting the outputs are stale. Please clear outputs (and reset execution_count) or re-run so the committed outputs correspond to the current code.

Suggested change
"\n",
"\n",
"❓ User: Find tables related to orders\n",
"============================================================\n",
"🧠 Agent thinking about: Find tables related to orders\n",
"--------------------------------------------------\n",
"🔧 Agent decided to use: search_tables: orders\n",
"📦 Data fetched: ['raw_orders', 'fact_orders', 'fact_orders', 'orders', 'orders', 'orders', 'orders', 'orders', 'orders', 'table_soldier_answer_8ad293a8']\n",
"--------------------------------------------------\n",
"🤖 Agent answer: I've searched for tables related to \"orders\" in our data catalog. Here are the results:\n",
"\n",
"We have found several tables that may be relevant to your query:\n",
"1. **raw_orders**: This table likely contains raw, unprocessed data related to orders.\n",
"2. **fact_orders**: This table appears to be a fact table, which is a type of table used in data warehousing to store measurable data, such as order quantities, amounts, or dates. There are multiple instances of this table in our search results.\n",
"3. **orders**: This table is directly named \"orders\" and may contain a wide range of data related to orders. There are multiple instances of this table in our search results, which could indicate different versions, updates, or copies of the same data.\n",
"4. **table_soldier_answer_8ad293a8**: This table seems unrelated to orders based on its name. It's possible that this result is a false positive or that the table contains some data related to orders that isn't immediately apparent from its name.\n",
"\n",
"To help you further, I can try to:\n",

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +25
"# LangChain + OpenMetadata Template\n",
"### Built by Baibhav Prateek | OpenMetadata Hackathon 2026\n",
"\n",
"## What is this?\n",
"A reusable template that connects AI to OpenMetadata.\n",
"Anyone can use this as a starting point for their own\n",
"AI-powered data catalog applications.\n",
"\n",
"## How to use this template:\n",
"1) Add your API keys\n",
"2) Run all cells in order\n",
"3) Ask your own questions\n",
"4) Customize the questions for your use case\n",
"\n",
"## Technologies used:\n",
"1) OpenMetadata API for metadata\n",
"2) Groq AI (LLaMA 3) for natural language processing\n",
"3) Python requests for API calls"
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The title/README call this a “LangChain + OpenMetadata Template”, but the notebook does not import or use LangChain at all (it directly calls Groq and requests). Either update the implementation to actually use LangChain primitives (e.g., LLM/Prompt/Tool abstractions), or rename the notebook and its description to avoid misleading users.

Copilot uses AI. Check for mistakes.
Comment on lines +79 to +105
"def tool_get_tables(limit=10):\n",
" \"\"\"Get list of tables from OpenMetadata\"\"\"\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params={\"limit\": limit}\n",
" )\n",
" tables = response.json().get(\"data\", [])\n",
" return [{\"name\": t.get(\"name\"), \n",
" \"description\": t.get(\"description\", \"No description\"),\n",
" \"columns\": len(t.get(\"columns\", []))} \n",
" for t in tables]\n",
"\n",
" \n",
"# Tool 2: Search for specific tables by keyword \n",
"\n",
"\n",
"def tool_search_tables(keyword):\n",
" \"\"\"Search for specific tables by keyword\"\"\"\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/search/query\",\n",
" headers=HEADERS,\n",
" params={\"q\": keyword, \"index\": \"table_search_index\", \"limit\": 5}\n",
" )\n",
" hits = response.json().get(\"hits\", {}).get(\"hits\", [])\n",
" return [h.get(\"_source\", {}).get(\"name\", \"\") for h in hits]\n",
"\n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The agent tool functions call the OpenMetadata REST API but do not validate the HTTP response status before parsing JSON. This can lead to confusing failures on auth/network errors. Please add response.raise_for_status() (or explicit status handling) and provide a clear error message when requests fail.

Copilot uses AI. Check for mistakes.
- Cleared all cell outputs from notebooks
- Removed pre-executed data for security
- Fixes security concern raised in code review
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Copilot AI review requested due to automatic review settings April 18, 2026 06:01
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 11 comments.

"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.9"
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notebook metadata declares Python 3.13.9, but this repository explicitly supports Python 3.9–3.11 for ingestion/SDK code. Please update the notebook kernel/language metadata to a supported version (e.g., 3.11) to avoid misleading users and compatibility issues.

Suggested change
"version": "3.13.9"
"version": "3.11"

Copilot uses AI. Check for mistakes.
Comment on lines +75 to +81
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params={\"limit\": 50}\n",
" )\n",
" data = response.json()\n",
" tables = data.get(\"data\", [])\n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_all_tables() only fetches a single page (limit=50), but the name implies it returns the full catalog. Either rename it to reflect that it’s a single page, or implement pagination using the API cursor (paging.after) so larger catalogs are handled correctly.

Suggested change
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params={\"limit\": 50}\n",
" )\n",
" data = response.json()\n",
" tables = data.get(\"data\", [])\n",
" tables = []\n",
" after = None\n",
"\n",
" while True:\n",
" params = {\"limit\": 50}\n",
" if after:\n",
" params[\"after\"] = after\n",
"\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params=params\n",
" )\n",
" data = response.json()\n",
" tables.extend(data.get(\"data\", []))\n",
"\n",
" paging = data.get(\"paging\", {})\n",
" after = paging.get(\"after\")\n",
" if not after:\n",
" break\n",
"\n",

Copilot uses AI. Check for mistakes.
Comment thread ingestion/examples/requirements.txt Outdated
@@ -0,0 +1,7 @@
openmetadata-ingestion
groq
google-genai
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

google-genai is listed as a dependency but it is not referenced anywhere in the notebooks/README in this PR. Please remove it from requirements.txt (or add a concrete usage example so the dependency is justified).

Suggested change
google-genai

Copilot uses AI. Check for mistakes.
Comment on lines +144 to +153
" if \"search_tables\" in decision:\n",
" keyword = decision.split(\":\")[-1].strip()\n",
" data = tool_search_tables(keyword)\n",
" tool_used = f\"search_tables('{keyword}')\"\n",
" elif \"get_databases\" in decision:\n",
" data = tool_get_databases()\n",
" tool_used = \"get_databases()\"\n",
" else:\n",
" data = tool_get_tables()\n",
" tool_used = \"get_tables()\"\n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tool selection parsing is brittle: if the model returns search_tables without a colon/keyword, decision.split(":")[-1] will produce search_tables as the keyword and run an unintended search. Please validate the decision format (exact match vs search_tables: <keyword> with non-empty keyword) and handle invalid outputs explicitly.

Suggested change
" if \"search_tables\" in decision:\n",
" keyword = decision.split(\":\")[-1].strip()\n",
" data = tool_search_tables(keyword)\n",
" tool_used = f\"search_tables('{keyword}')\"\n",
" elif \"get_databases\" in decision:\n",
" data = tool_get_databases()\n",
" tool_used = \"get_databases()\"\n",
" else:\n",
" data = tool_get_tables()\n",
" tool_used = \"get_tables()\"\n",
" normalized_decision = decision.strip()\n",
" if normalized_decision == \"get_tables\":\n",
" data = tool_get_tables()\n",
" tool_used = \"get_tables()\"\n",
" elif normalized_decision == \"get_databases\":\n",
" data = tool_get_databases()\n",
" tool_used = \"get_databases()\"\n",
" elif normalized_decision.startswith(\"search_tables:\"):\n",
" keyword = normalized_decision.partition(\":\")[2].strip()\n",
" if not keyword:\n",
" raise ValueError(\n",
" \"Invalid tool decision: 'search_tables' requires a non-empty keyword.\"\n",
" )\n",
" data = tool_search_tables(keyword)\n",
" tool_used = f\"search_tables('{keyword}')\"\n",
" else:\n",
" raise ValueError(\n",
" \"Invalid tool decision. Expected one of 'get_tables', 'get_databases', or 'search_tables: <keyword>'.\"\n",
" )\n",

Copilot uses AI. Check for mistakes.
Comment on lines +179 to +208
"total = len(df)\n",
"has_description = (df[\"Has Description\"] == \"✅\").sum()\n",
"missing_description = (df[\"Has Description\"] == \"❌\").sum()\n",
"has_owner = (df[\"Has Owner\"] == \"✅\").sum()\n",
"missing_owner = (df[\"Has Owner\"] == \"❌\").sum()\n",
"total_columns = df[\"Total Columns\"].sum()\n",
"columns_missing_desc = df[\"Columns Missing Desc\"].sum()\n",
"\n",
"print(\"=\" * 50)\n",
"print(\" 📊 OPENMETADATA HEALTH REPORT\")\n",
"print(\"=\" * 50)\n",
"print(f\" Total Tables Analyzed : {total}\")\n",
"print(f\" ✅ Have Description : {has_description} ({round(has_description/total*100)}%)\")\n",
"print(f\" ❌ Missing Description : {missing_description} ({round(missing_description/total*100)}%)\")\n",
"print(f\" ✅ Have Owner : {has_owner} ({round(has_owner/total*100)}%)\")\n",
"print(f\" ❌ Missing Owner : {missing_owner} ({round(missing_owner/total*100)}%)\")\n",
"print(f\" Total Columns : {total_columns}\")\n",
"print(f\" Columns Missing Desc : {columns_missing_desc}\")\n",
"print(\"=\" * 50)\n",
"\n",
"# Health Score\n",
"score = round(((has_description + has_owner) / (total * 2)) * 100)\n",
"print(f\"\\n 🏥 Overall Health Score: {score}/100\")\n",
"if score >= 70:\n",
" print(\" Status: 🟢 HEALTHY\")\n",
"elif score >= 40:\n",
" print(\" Status: 🟡 NEEDS ATTENTION\")\n",
"else:\n",
" print(\" Status: 🔴 CRITICAL\")\n",
"print(\"=\" * 50)"
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The summary report logic is duplicated across multiple consecutive cells, which makes maintenance harder and risks inconsistencies. Please keep a single summary implementation (or refactor into a helper) and remove the duplicated cell.

Suggested change
"total = len(df)\n",
"has_description = (df[\"Has Description\"] == \"\").sum()\n",
"missing_description = (df[\"Has Description\"] == \"\").sum()\n",
"has_owner = (df[\"Has Owner\"] == \"\").sum()\n",
"missing_owner = (df[\"Has Owner\"] == \"\").sum()\n",
"total_columns = df[\"Total Columns\"].sum()\n",
"columns_missing_desc = df[\"Columns Missing Desc\"].sum()\n",
"\n",
"print(\"=\" * 50)\n",
"print(\" 📊 OPENMETADATA HEALTH REPORT\")\n",
"print(\"=\" * 50)\n",
"print(f\" Total Tables Analyzed : {total}\")\n",
"print(f\" ✅ Have Description : {has_description} ({round(has_description/total*100)}%)\")\n",
"print(f\" ❌ Missing Description : {missing_description} ({round(missing_description/total*100)}%)\")\n",
"print(f\" ✅ Have Owner : {has_owner} ({round(has_owner/total*100)}%)\")\n",
"print(f\" ❌ Missing Owner : {missing_owner} ({round(missing_owner/total*100)}%)\")\n",
"print(f\" Total Columns : {total_columns}\")\n",
"print(f\" Columns Missing Desc : {columns_missing_desc}\")\n",
"print(\"=\" * 50)\n",
"\n",
"# Health Score\n",
"score = round(((has_description + has_owner) / (total * 2)) * 100)\n",
"print(f\"\\n 🏥 Overall Health Score: {score}/100\")\n",
"if score >= 70:\n",
" print(\" Status: 🟢 HEALTHY\")\n",
"elif score >= 40:\n",
" print(\" Status: 🟡 NEEDS ATTENTION\")\n",
"else:\n",
" print(\" Status: 🔴 CRITICAL\")\n",
"print(\"=\" * 50)"
"def print_summary_report(df):\n",
" total = len(df)\n",
" has_description = (df[\"Has Description\"] == \"\").sum()\n",
" missing_description = (df[\"Has Description\"] == \"\").sum()\n",
" has_owner = (df[\"Has Owner\"] == \"\").sum()\n",
" missing_owner = (df[\"Has Owner\"] == \"\").sum()\n",
" total_columns = df[\"Total Columns\"].sum()\n",
" columns_missing_desc = df[\"Columns Missing Desc\"].sum()\n",
"\n",
" description_pct = round(has_description / total * 100) if total else 0\n",
" missing_description_pct = round(missing_description / total * 100) if total else 0\n",
" owner_pct = round(has_owner / total * 100) if total else 0\n",
" missing_owner_pct = round(missing_owner / total * 100) if total else 0\n",
" score = round(((has_description + has_owner) / (total * 2)) * 100) if total else 0\n",
"\n",
" print(\"=\" * 50)\n",
" print(\" 📊 OPENMETADATA HEALTH REPORT\")\n",
" print(\"=\" * 50)\n",
" print(f\" Total Tables Analyzed : {total}\")\n",
" print(f\" ✅ Have Description : {has_description} ({description_pct}%)\")\n",
" print(f\" ❌ Missing Description : {missing_description} ({missing_description_pct}%)\")\n",
" print(f\" ✅ Have Owner : {has_owner} ({owner_pct}%)\")\n",
" print(f\" ❌ Missing Owner : {missing_owner} ({missing_owner_pct}%)\")\n",
" print(f\" Total Columns : {total_columns}\")\n",
" print(f\" Columns Missing Desc : {columns_missing_desc}\")\n",
" print(\"=\" * 50)\n",
" print(f\"\\n 🏥 Overall Health Score: {score}/100\")\n",
" if score >= 70:\n",
" print(\" Status: 🟢 HEALTHY\")\n",
" elif score >= 40:\n",
" print(\" Status: 🟡 NEEDS ATTENTION\")\n",
" else:\n",
" print(\" Status: 🔴 CRITICAL\")\n",
" print(\"=\" * 50)\n",
"\n",
"print_summary_report(df)"

Copilot uses AI. Check for mistakes.
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.9"
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notebook metadata declares Python 3.13.9, but this repository explicitly supports Python 3.9–3.11 for ingestion/SDK code. Please update the notebook kernel/language metadata to a supported version (e.g., 3.11) to avoid misleading users and compatibility issues.

Suggested change
"version": "3.13.9"
"version": "3.11"

Copilot uses AI. Check for mistakes.
Comment on lines +65 to +69
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params={\"limit\": limit}\n",
" )\n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All OpenMetadata API calls use response.json() without checking response.status_code / raise_for_status(). If auth fails or the server returns non-JSON, this will throw and obscure the real error. Please add status checking (and a clearer error message) before parsing JSON in these tool functions.

Copilot uses AI. Check for mistakes.
Comment on lines +151 to +160
"print(f\" ✅ Have Description : {has_description} ({round(has_description/total*100)}%)\")\n",
"print(f\" ❌ Missing Description : {missing_description} ({round(missing_description/total*100)}%)\")\n",
"print(f\" ✅ Have Owner : {has_owner} ({round(has_owner/total*100)}%)\")\n",
"print(f\" ❌ Missing Owner : {missing_owner} ({round(missing_owner/total*100)}%)\")\n",
"print(f\" Total Columns : {total_columns}\")\n",
"print(f\" Columns Missing Desc : {columns_missing_desc}\")\n",
"print(\"=\" * 50)\n",
"\n",
"# Health Score\n",
"score = round(((has_description + has_owner) / (total * 2)) * 100)\n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the catalog has zero tables, total will be 0 and the percentage calculations (has_description/total*100, etc.) will raise ZeroDivisionError. Please guard for total == 0 and print a sensible empty-catalog summary (and ensure score is defined before it’s used later).

Suggested change
"print(f\" ✅ Have Description : {has_description} ({round(has_description/total*100)}%)\")\n",
"print(f\" ❌ Missing Description : {missing_description} ({round(missing_description/total*100)}%)\")\n",
"print(f\" ✅ Have Owner : {has_owner} ({round(has_owner/total*100)}%)\")\n",
"print(f\" ❌ Missing Owner : {missing_owner} ({round(missing_owner/total*100)}%)\")\n",
"print(f\" Total Columns : {total_columns}\")\n",
"print(f\" Columns Missing Desc : {columns_missing_desc}\")\n",
"print(\"=\" * 50)\n",
"\n",
"# Health Score\n",
"score = round(((has_description + has_owner) / (total * 2)) * 100)\n",
"\n",
"if total == 0:\n",
" print(\" ✅ Have Description : 0 (0%)\")\n",
" print(\" ❌ Missing Description : 0 (0%)\")\n",
" print(\" ✅ Have Owner : 0 (0%)\")\n",
" print(\" ❌ Missing Owner : 0 (0%)\")\n",
" print(f\" Total Columns : {total_columns}\")\n",
" print(f\" Columns Missing Desc : {columns_missing_desc}\")\n",
" print(\"=\" * 50)\n",
" print(\"\\n No tables found in the catalog.\")\n",
" score = 0\n",
"else:\n",
" print(f\" ✅ Have Description : {has_description} ({round(has_description / total * 100)}%)\")\n",
" print(f\" ❌ Missing Description : {missing_description} ({round(missing_description / total * 100)}%)\")\n",
" print(f\" ✅ Have Owner : {has_owner} ({round(has_owner / total * 100)}%)\")\n",
" print(f\" ❌ Missing Owner : {missing_owner} ({round(missing_owner / total * 100)}%)\")\n",
" print(f\" Total Columns : {total_columns}\")\n",
" print(f\" Columns Missing Desc : {columns_missing_desc}\")\n",
" print(\"=\" * 50)\n",
"\n",
" # Health Score\n",
" score = round(((has_description + has_owner) / (total * 2)) * 100)\n",
"\n",

Copilot uses AI. Check for mistakes.
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.9"
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notebook metadata declares Python 3.13.9, but this repository explicitly supports Python 3.9–3.11 for ingestion/SDK code. Please update the notebook kernel/language metadata to a supported version (e.g., 3.11) to avoid misleading users and compatibility issues.

Suggested change
"version": "3.13.9"
"version": "3.11"

Copilot uses AI. Check for mistakes.
Comment thread ingestion/examples/README.md Outdated
Comment on lines +36 to +39
## Technologies Used
- OpenMetadata API
- Groq AI (LLaMA 3.3 70b)
- Python, Pandas, Matplotlib
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description/issue mention using the OpenMetadata Python SDK, but the notebooks/README currently use raw REST calls via requests (and don’t demonstrate metadata.sdk). Please either update the examples to use the SDK client APIs, or adjust the README to clearly state these are REST-based examples.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Comment thread ingestion/examples/langchain_openmetadata_template.ipynb Outdated
Comment on lines +108 to +109
"if tables:\n",
" print(f\"✅ Found {len(tables)} tables!\")"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: Division by zero still reachable when no tables returned

The new error handling in get_all_tables() correctly returns [] on failure, but downstream code at line ~183 still computes score = round(((has_description + has_owner) / (total * 2)) * 100) where total = len(df). When tables is empty, total is 0 and this raises ZeroDivisionError. The guard added at line 108 (if tables: print(...)) only suppresses the success message but doesn't prevent the rest of the notebook from executing with an empty list.

Suggested fix:

Guard the downstream cells or add an early exit:

tables = get_all_tables()
if not tables:
    print("⚠️ No tables to analyze. Exiting.")
else:
    print(f"✅ Found {len(tables)} tables!")

And in the score calculation cell:
if total == 0:
    print("No tables to score.")
else:
    score = round(((has_description + has_owner) / (total * 2)) * 100)

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

Copilot AI review requested due to automatic review settings April 18, 2026 06:22
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 10 comments.

Comment on lines +34 to +49
"import requests\n",
"import json\n",
"from groq import Groq\n",
"\n",
"# Your credentials\n",
"GROQ_API_KEY = \"paste api key here\"\n",
"BASE_URL = \"https://sandbox.open-metadata.org\"\n",
"TOKEN = \"paste your tokens here\"\n",
"\n",
"HEADERS = {\n",
" \"Authorization\": f\"Bearer {TOKEN}\",\n",
" \"Content-Type\": \"application/json\"\n",
"}\n",
"\n",
"client = Groq(api_key=GROQ_API_KEY)\n",
"print(\"✅ Agent setup complete!\")"
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These recipes are described as “AI SDK recipes”, but this notebook uses direct REST calls via requests and does not use the OpenMetadata Python SDK (metadata.sdk). Since openmetadata-ingestion is included as a dependency, consider switching table listing/search to the SDK APIs (see ingestion/src/metadata/sdk/README.md for configure(), Table.list(), Search.search()) so the example showcases the SDK rather than raw HTTP.

Suggested change
"import requests\n",
"import json\n",
"from groq import Groq\n",
"\n",
"# Your credentials\n",
"GROQ_API_KEY = \"paste api key here\"\n",
"BASE_URL = \"https://sandbox.open-metadata.org\"\n",
"TOKEN = \"paste your tokens here\"\n",
"\n",
"HEADERS = {\n",
" \"Authorization\": f\"Bearer {TOKEN}\",\n",
" \"Content-Type\": \"application/json\"\n",
"}\n",
"\n",
"client = Groq(api_key=GROQ_API_KEY)\n",
"print(\"✅ Agent setup complete!\")"
"import json\n",
"from groq import Groq\n",
"from metadata.sdk import configure\n",
"\n",
"# Your credentials\n",
"GROQ_API_KEY = \"paste api key here\"\n",
"BASE_URL = \"https://sandbox.open-metadata.org\"\n",
"TOKEN = \"paste your tokens here\"\n",
"\n",
"# Configure the OpenMetadata SDK so the notebook uses SDK APIs\n",
"# such as Table.list() and Search.search() instead of raw REST calls.\n",
"ometa = configure(server=BASE_URL, api_key=TOKEN)\n",
"\n",
"client = Groq(api_key=GROQ_API_KEY)\n",
"print(\"✅ Agent setup complete with OpenMetadata SDK!\")"

Copilot uses AI. Check for mistakes.
Comment on lines +247 to +248
"version": "3.13.9"
}
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notebook metadata lists Python 3.13.9, which is outside the ingestion module’s supported versions (e.g., ingestion/noxfile.py lists 3.10–3.12). Please update the kernel/language metadata to a supported version to reduce confusion when users run these notebooks.

Copilot uses AI. Check for mistakes.
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.9"
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notebook metadata lists Python 3.13.9, which is outside the ingestion module’s supported versions (e.g., ingestion/noxfile.py lists 3.10–3.12). Please update the kernel/language metadata to a supported version to reduce confusion when users run these notebooks.

Suggested change
"version": "3.13.9"
"version": "3.11.0"

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,6 @@
openmetadata-ingestion
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

openmetadata-ingestion is listed here, but the added notebooks currently use raw requests calls and do not import/use the Python SDK (metadata.sdk). Either update the notebooks to use the SDK (preferred for “SDK recipes”) or remove this dependency to avoid suggesting it’s required.

Suggested change
openmetadata-ingestion

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +77
" tables = response.json().get(\"data\", [])\n",
" return [{\"name\": t.get(\"name\"),\n",
" \"description\": t.get(\"description\", \"No description\"),\n",
" \"columns\": len(t.get(\"columns\", []))}\n",
" for t in tables]\n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/api/v1/tables is called without a fields query param, so columns is not returned by default (empty requested fields). As a result, len(t.get("columns", [])) will be 0 for all tables, making the “columns” info misleading. Either request the columns field explicitly via fields=columns or drop this column count from the tool output.

Copilot uses AI. Check for mistakes.
Comment on lines +196 to +200
"# Health Score\n",
"score = round(((has_description + has_owner) / (total * 2)) * 100)\n",
"print(f\"\\n 🏥 Overall Health Score: {score}/100\")\n",
"if score >= 70:\n",
" print(\" Status: 🟢 HEALTHY\")\n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this cell, the health score is computed and printed again after the if total == 0 guard. If total is 0, variables like has_description/has_owner are never set, so this block will raise a NameError (and it also duplicates the output). Consider removing the duplicate block or moving score computation entirely inside the else branch with proper initialization.

Copilot uses AI. Check for mistakes.
Comment on lines +215 to +219
"# Print a nice summary report\n",
"total = len(df)\n",
"has_description = (df[\"Has Description\"] == \"✅\").sum()\n",
"missing_description = (df[\"Has Description\"] == \"❌\").sum()\n",
"has_owner = (df[\"Has Owner\"] == \"✅\").sum()\n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This second summary cell repeats the same calculations/printing as the previous one but without the total == 0 guard, which can lead to division-by-zero errors when the catalog has no tables. Recommend deleting this duplicate cell (or keeping a single summary path that handles the empty case safely).

Copilot uses AI. Check for mistakes.
Comment on lines +74 to +95
"# Fetch limited tables with error handling\n",
"def get_all_tables():\n",
" try:\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params={\"limit\": 50}\n",
" )\n",
" # Check if request was successful\n",
" if response.status_code != 200:\n",
" print(f\"❌ Error: Server returned {response.status_code}\")\n",
" return []\n",
" \n",
" data = response.json()\n",
" tables = data.get(\"data\", [])\n",
" \n",
" if not tables:\n",
" print(\"⚠️ No tables found!\")\n",
" return []\n",
" \n",
" return tables\n",
" \n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_all_tables() currently requests only limit=50 tables and does not paginate, but the name and later reporting imply you are analyzing the whole catalog. Either implement pagination (iterate using after/paging until exhausted) or rename the function/outputs to make the limit explicit.

Suggested change
"# Fetch limited tables with error handling\n",
"def get_all_tables():\n",
" try:\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params={\"limit\": 50}\n",
" )\n",
" # Check if request was successful\n",
" if response.status_code != 200:\n",
" print(f\"❌ Error: Server returned {response.status_code}\")\n",
" return []\n",
" \n",
" data = response.json()\n",
" tables = data.get(\"data\", [])\n",
" \n",
" if not tables:\n",
" print(\"⚠️ No tables found!\")\n",
" return []\n",
" \n",
" return tables\n",
" \n",
"# Fetch all tables with pagination and error handling\n",
"def get_all_tables():\n",
" try:\n",
" tables = []\n",
" after = None\n",
"\n",
" while True:\n",
" params = {\"limit\": 50}\n",
" if after:\n",
" params[\"after\"] = after\n",
"\n",
" response = requests.get(\n",
" f\"{BASE_URL}/api/v1/tables\",\n",
" headers=HEADERS,\n",
" params=params\n",
" )\n",
"\n",
" # Check if request was successful\n",
" if response.status_code != 200:\n",
" print(f\"❌ Error: Server returned {response.status_code}\")\n",
" return []\n",
"\n",
" data = response.json()\n",
" page_tables = data.get(\"data\", [])\n",
" tables.extend(page_tables)\n",
"\n",
" after = data.get(\"paging\", {}).get(\"after\")\n",
" if not after:\n",
" break\n",
"\n",
" if not tables:\n",
" print(\"⚠️ No tables found!\")\n",
" return []\n",
"\n",
" return tables\n",
"\n",

Copilot uses AI. Check for mistakes.
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.9"
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notebook metadata lists Python 3.13.9. The ingestion module’s supported versions are lower (e.g., ingestion/noxfile.py lists 3.10–3.12), so this kernel metadata is likely to confuse users and may not be runnable in the supported envs. Please update the notebook kernel/language metadata to a supported version (or omit the patch version).

Suggested change
"version": "3.13.9"
"version": "3.11"

Copilot uses AI. Check for mistakes.
Comment on lines +124 to +128
" name = table.get(\"name\", \"Unknown\")\n",
" description = table.get(\"description\", \"\")\n",
" owner = table.get(\"owner\", None)\n",
" followers = table.get(\"followers\", 0)\n",
" tags = table.get(\"tags\", [])\n",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The /api/v1/tables list call (without a fields query param) returns tables with an empty fields set, so columns/owners are typically not included (see EntityUtil.Fields behavior). As a result, columns = table.get("columns", []) will be empty and table.get("owner") will always be None (the API uses owners, not owner), making the health metrics inaccurate. Pass an explicit fields param (e.g., include columns,owners) and read from the correct owners field.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@gitar-bot
Copy link
Copy Markdown

gitar-bot bot commented Apr 18, 2026

Code Review ⚠️ Changes requested 4 resolved / 8 findings

Integrates new AI SDK recipes but requires fixes for prompt injection vulnerabilities in the AI agent and division-by-zero errors in the health report. Resolved several documentation inconsistencies, notebook artifacts, and placeholder typos.

⚠️ Security: Prompt injection via unsanitized user input and API data

📄 ingestion/examples/openmetadata_ai_agent.ipynb:147-158 📄 ingestion/examples/openmetadata_ai_agent.ipynb:183-188 📄 ingestion/examples/langchain_openmetadata_template.ipynb:140-145

In openmetadata_ai_agent.ipynb, user_question is interpolated directly into the LLM prompt (line 147 decision_prompt and line 183 final_prompt), and raw API response data is also injected into prompts (line 186 Data retrieved: {data}). A malicious table name or description in OpenMetadata could manipulate the LLM's behavior (indirect prompt injection). Similarly in langchain_openmetadata_template.ipynb, table names from the API are injected into the prompt at line 141.

For example recipes this may be acceptable, but consider adding a note about sanitization for production use, or at minimum escaping/truncating the data before prompt injection.

⚠️ Bug: Division by zero when no tables are returned

📄 ingestion/examples/metadata_health_report.ipynb:250-253 📄 ingestion/examples/metadata_health_report.ipynb:259 📄 ingestion/examples/metadata_health_report.ipynb:312-315 📄 ingestion/examples/metadata_health_report.ipynb:321

In metadata_health_report.ipynb, the health score calculation uses total * 2 as a divisor (line 259/321) and the percentage calculations use total as a divisor (lines 250-253/312-315). If the API returns zero tables, total will be 0 and all these expressions will raise ZeroDivisionError. An example/recipe notebook should handle this gracefully since users may run it against an empty or misconfigured instance.

Suggested fix
Add a guard before the summary block:

if total == 0:
    print("No tables found. Check your connection and token.")
else:
    # ... existing summary code ...
⚠️ Quality: Duplicate notebook cell: summary report appears twice

📄 ingestion/examples/metadata_health_report.ipynb:236-250 📄 ingestion/examples/metadata_health_report.ipynb:298-312

In metadata_health_report.ipynb, cells at lines 236-268 and 298-330 contain nearly identical code for printing the health report summary. The first version includes "Built for OpenMetadata Hackathon 2026" text while the second doesn't, but otherwise they are duplicates. This appears to be an editing artifact — one of them should be removed.

⚠️ Bug: Division by zero still reachable when no tables returned

📄 ingestion/examples/metadata_health_report.ipynb:108-109

The new error handling in get_all_tables() correctly returns [] on failure, but downstream code at line ~183 still computes score = round(((has_description + has_owner) / (total * 2)) * 100) where total = len(df). When tables is empty, total is 0 and this raises ZeroDivisionError. The guard added at line 108 (if tables: print(...)) only suppresses the success message but doesn't prevent the rest of the notebook from executing with an empty list.

Suggested fix
Guard the downstream cells or add an early exit:

tables = get_all_tables()
if not tables:
    print("⚠️ No tables to analyze. Exiting.")
else:
    print(f"✅ Found {len(tables)} tables!")

And in the score calculation cell:
if total == 0:
    print("No tables to score.")
else:
    score = round(((has_description + has_owner) / (total * 2)) * 100)
✅ 4 resolved
Security: Notebooks contain pre-executed output with live API data

📄 ingestion/examples/metadata_health_report.ipynb:31-45 📄 ingestion/examples/metadata_health_report.ipynb:211-225 📄 ingestion/examples/metadata_health_report.ipynb:337-351 📄 ingestion/examples/openmetadata_ai_agent.ipynb:31-45 📄 ingestion/examples/openmetadata_ai_agent.ipynb:66-71 📄 ingestion/examples/openmetadata_ai_agent.ipynb:128-135 📄 ingestion/examples/openmetadata_ai_agent.ipynb:206-220 📄 ingestion/examples/langchain_openmetadata_template.ipynb:33-40 📄 ingestion/examples/langchain_openmetadata_template.ipynb:117-126 📄 ingestion/examples/langchain_openmetadata_template.ipynb:164-178
All three notebooks are committed with pre-executed cell outputs containing live data from the sandbox environment (table names, database names, full API responses). This is a data exposure risk — outputs like ACMECORP_GOLD, ACCOUNTS with "sensitive financial balance information", and full schema details are baked into the repository. Additionally, the executed outputs make the notebooks larger than necessary and will cause noisy diffs on future changes.

Clear all cell outputs before committing. In Jupyter: Kernel → Restart & Clear Output, then save. Consider adding a .gitattributes or pre-commit hook (e.g., nbstripout) to prevent future commits with outputs.

Quality: README missing newline at end of file

📄 ingestion/examples/README.md:40
The README.md file is missing a trailing newline character, which is a POSIX convention and will show as a diff warning.

Quality: Mismatched demo questions between cell source and output

📄 ingestion/examples/openmetadata_ai_agent.ipynb:284-288 📄 ingestion/examples/openmetadata_ai_agent.ipynb:215-229
In openmetadata_ai_agent.ipynb, the source code defines test_questions as questions about customer info, financial data, and analyst recommendations (lines 284-288), but the cell output shows completely different questions: "Show me all available databases", "Find tables related to orders", and "What tables do we have in our catalog?" (lines 215-277). This indicates the code was modified after execution without re-running, which will confuse users following the recipe.

Security: Typo in placeholder: "grok" should be "groq"

📄 ingestion/examples/langchain_openmetadata_template.ipynb:40
The placeholder API key string in the LangChain template says "grok api key" but the service is Groq (not Grok). This is confusing for users since Grok is a different AI product (xAI). The other two notebooks use clearer placeholders like "paste api key here".

🤖 Prompt for agents
Code Review: Integrates new AI SDK recipes but requires fixes for prompt injection vulnerabilities in the AI agent and division-by-zero errors in the health report. Resolved several documentation inconsistencies, notebook artifacts, and placeholder typos.

1. ⚠️ Security: Prompt injection via unsanitized user input and API data
   Files: ingestion/examples/openmetadata_ai_agent.ipynb:147-158, ingestion/examples/openmetadata_ai_agent.ipynb:183-188, ingestion/examples/langchain_openmetadata_template.ipynb:140-145

   In `openmetadata_ai_agent.ipynb`, `user_question` is interpolated directly into the LLM prompt (line 147 `decision_prompt` and line 183 `final_prompt`), and raw API response data is also injected into prompts (line 186 `Data retrieved: {data}`). A malicious table name or description in OpenMetadata could manipulate the LLM's behavior (indirect prompt injection). Similarly in `langchain_openmetadata_template.ipynb`, table names from the API are injected into the prompt at line 141.
   
   For example recipes this may be acceptable, but consider adding a note about sanitization for production use, or at minimum escaping/truncating the data before prompt injection.

2. ⚠️ Bug: Division by zero when no tables are returned
   Files: ingestion/examples/metadata_health_report.ipynb:250-253, ingestion/examples/metadata_health_report.ipynb:259, ingestion/examples/metadata_health_report.ipynb:312-315, ingestion/examples/metadata_health_report.ipynb:321

   In `metadata_health_report.ipynb`, the health score calculation uses `total * 2` as a divisor (line 259/321) and the percentage calculations use `total` as a divisor (lines 250-253/312-315). If the API returns zero tables, `total` will be 0 and all these expressions will raise `ZeroDivisionError`. An example/recipe notebook should handle this gracefully since users may run it against an empty or misconfigured instance.

   Suggested fix:
   Add a guard before the summary block:
   
   if total == 0:
       print("No tables found. Check your connection and token.")
   else:
       # ... existing summary code ...

3. ⚠️ Quality: Duplicate notebook cell: summary report appears twice
   Files: ingestion/examples/metadata_health_report.ipynb:236-250, ingestion/examples/metadata_health_report.ipynb:298-312

   In `metadata_health_report.ipynb`, cells at lines 236-268 and 298-330 contain nearly identical code for printing the health report summary. The first version includes "Built for OpenMetadata Hackathon 2026" text while the second doesn't, but otherwise they are duplicates. This appears to be an editing artifact — one of them should be removed.

4. ⚠️ Bug: Division by zero still reachable when no tables returned
   Files: ingestion/examples/metadata_health_report.ipynb:108-109

   The new error handling in `get_all_tables()` correctly returns `[]` on failure, but downstream code at line ~183 still computes `score = round(((has_description + has_owner) / (total * 2)) * 100)` where `total = len(df)`. When `tables` is empty, `total` is 0 and this raises `ZeroDivisionError`. The guard added at line 108 (`if tables: print(...)`) only suppresses the success message but doesn't prevent the rest of the notebook from executing with an empty list.

   Suggested fix:
   Guard the downstream cells or add an early exit:
   
   tables = get_all_tables()
   if not tables:
       print("⚠️ No tables to analyze. Exiting.")
   else:
       print(f"✅ Found {len(tables)} tables!")
   
   And in the score calculation cell:
   if total == 0:
       print("No tables to score.")
   else:
       score = round(((has_description + has_owner) / (total * 2)) * 100)

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Metadata AI SDK Starter Templates / Recipes

2 participants