Skip to content
Merged
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
5fd292a
break the code to core and api
gkorland Sep 6, 2025
1848e0d
refactor load steps
gkorland Sep 6, 2025
383d303
Bump litellm from 1.76.2 to 1.76.3
dependabot[bot] Sep 8, 2025
b76bca5
Bump pytest from 8.4.1 to 8.4.2
dependabot[bot] Sep 8, 2025
285ace8
Bump pytest-playwright from 0.7.0 to 0.7.1
dependabot[bot] Sep 8, 2025
432afb0
Bump @typescript-eslint/parser from 8.40.0 to 8.42.0 in /app
dependabot[bot] Sep 8, 2025
45a5e13
Bump eslint from 9.34.0 to 9.35.0 in /app
dependabot[bot] Sep 8, 2025
d1cca0e
Merge branch 'staging' into lib
galshubeli Sep 10, 2025
f9aa51b
lint
galshubeli Sep 10, 2025
2e0c5fd
Merge pull request #226 from FalkorDB/lib
gkorland Sep 11, 2025
edf15d1
Merge branch 'staging' into dependabot/npm_and_yarn/app/staging/types…
gkorland Sep 11, 2025
97f9825
Merge pull request #236 from FalkorDB/dependabot/npm_and_yarn/app/sta…
gkorland Sep 11, 2025
ef4939b
Merge branch 'staging' into dependabot/npm_and_yarn/app/staging/eslin…
gkorland Sep 11, 2025
e7d1c96
Merge pull request #237 from FalkorDB/dependabot/npm_and_yarn/app/sta…
gkorland Sep 11, 2025
df57d54
Merge branch 'staging' into dependabot/pip/staging/pytest-playwright-…
gkorland Sep 11, 2025
3bb1279
Merge pull request #234 from FalkorDB/dependabot/pip/staging/pytest-p…
gkorland Sep 11, 2025
85142f5
Merge branch 'staging' into dependabot/pip/staging/pytest-8.4.2
gkorland Sep 11, 2025
960d15d
Merge pull request #233 from FalkorDB/dependabot/pip/staging/pytest-8…
gkorland Sep 11, 2025
0b09b47
Merge branch 'staging' into dependabot/pip/staging/litellm-1.76.3
gkorland Sep 11, 2025
f883112
Merge pull request #232 from FalkorDB/dependabot/pip/staging/litellm-…
gkorland Sep 11, 2025
9dea5e1
Bump @typescript-eslint/eslint-plugin from 8.40.0 to 8.42.0 in /app
dependabot[bot] Sep 11, 2025
fb07508
Bump playwright from 1.54.0 to 1.55.0
dependabot[bot] Sep 11, 2025
d88b4d0
Merge branch 'staging' into dependabot/pip/staging/playwright-1.55.0
gkorland Sep 11, 2025
46faf48
Merge pull request #231 from FalkorDB/dependabot/pip/staging/playwrig…
gkorland Sep 11, 2025
6b0bb3b
Merge branch 'staging' into dependabot/npm_and_yarn/app/staging/types…
gkorland Sep 11, 2025
684d8c2
Merge pull request #235 from FalkorDB/dependabot/npm_and_yarn/app/sta…
gkorland Sep 11, 2025
945f187
add mcp registry
gkorland Sep 11, 2025
9a5bf2f
Merge pull request #247 from FalkorDB/mcp-reg
gkorland Sep 11, 2025
8edc9a6
add url
gkorland Sep 11, 2025
b421f11
Merge branch 'staging' into mcp-reg
gkorland Sep 11, 2025
3cd62e6
Merge pull request #248 from FalkorDB/mcp-reg
gkorland Sep 11, 2025
54d84c1
update server
gkorland Sep 11, 2025
fdaabcb
fix graphs_list
gkorland Sep 11, 2025
18f74ee
Fix: Convert null to boolean in dropdown isDemo parameter
guglielmo Sep 15, 2025
5d9e35e
Bump pytest-asyncio from 1.1.0 to 1.2.0
dependabot[bot] Sep 15, 2025
699d0da
Bump litellm from 1.76.3 to 1.77.1
dependabot[bot] Sep 15, 2025
14d4d99
Merge pull request #251 from FalkorDB/dependabot/pip/staging/litellm-…
gkorland Sep 16, 2025
5e2e7cb
Merge branch 'staging' into dependabot/pip/staging/pytest-asyncio-1.2.0
gkorland Sep 16, 2025
2bdde8f
Merge pull request #250 from FalkorDB/dependabot/pip/staging/pytest-a…
gkorland Sep 16, 2025
7f73509
Merge branch 'staging' into fix/dropdown-isDemo-null-error
gkorland Sep 16, 2025
7c387e4
Merge pull request #249 from guglielmo/fix/dropdown-isDemo-null-error
galshubeli Sep 16, 2025
21e1f75
Bump authlib from 1.6.3 to 1.6.4
dependabot[bot] Sep 22, 2025
7ef3ba6
Add Contributor Covenant Code of Conduct
gkorland Sep 27, 2025
81d52b1
Merge pull request #255 from FalkorDB/dependabot/pip/staging/authlib-…
gkorland Sep 27, 2025
b57fd0c
Update wordlist.txt
gkorland Sep 27, 2025
7841d05
Delete wordlist.dic
gkorland Sep 27, 2025
67a5430
update deps
gkorland Sep 27, 2025
7f4782e
Merge pull request #264 from FalkorDB/update-deps
gkorland Sep 27, 2025
30e16bb
Bump uvicorn from 0.35.0 to 0.36.0
dependabot[bot] Sep 27, 2025
5b95777
fix docker build
gkorland Sep 27, 2025
1d6f768
Merge branch 'staging' into update-deps
gkorland Sep 27, 2025
79135a1
Merge pull request #265 from FalkorDB/update-deps
gkorland Sep 27, 2025
be80120
Merge branch 'staging' into dependabot/pip/staging/uvicorn-0.36.0
gkorland Sep 27, 2025
2a5779b
Merge pull request #261 from FalkorDB/dependabot/pip/staging/uvicorn-…
gkorland Sep 27, 2025
4ae9ff0
Merge branch 'staging' into gkorland-patch-2
gkorland Sep 27, 2025
4b1dc37
Merge pull request #263 from FalkorDB/gkorland-patch-2
gkorland Sep 27, 2025
99b5354
update all files to python12
gkorland Oct 2, 2025
0d2f346
Merge pull request #270 from FalkorDB/python12
gkorland Oct 2, 2025
d8f6011
Bump fastapi from 0.117.1 to 0.118.0
dependabot[bot] Oct 2, 2025
63608c5
Merge pull request #267 from FalkorDB/dependabot/pip/staging/fastapi-…
gkorland Oct 2, 2025
0a2b47e
move to fastmcp
gkorland Oct 8, 2025
caf4ad7
move the route and mcp init to start
gkorland Oct 8, 2025
f7b8cf3
set tags
gkorland Oct 8, 2025
8a47af9
fix lint
gkorland Oct 8, 2025
44c942e
all should be tools
gkorland Oct 8, 2025
db3b9db
Apply suggestion from @Copilot
gkorland Oct 8, 2025
8c6bd17
make sure tags are set
gkorland Oct 8, 2025
4c1d717
fix lint
gkorland Oct 8, 2025
71bfe07
Merge pull request #280 from FalkorDB/fastmcp
gkorland Oct 8, 2025
0b41046
Update api/core/text2sql.py
gkorland Oct 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ USER root
# Copy Python 3.12 from the python base image
COPY --from=python-base /usr/local /usr/local

# Install netcat for wait loop in start.sh
RUN apt-get update && apt-get install -y \
# Install netcat for wait loop in start.sh and system build tools needed for
# compiling Python wheels (g++, make, libc-dev)
RUN apt-get update && apt-get install -y --no-install-recommends \
netcat-openbsd \
git \
build-essential \
&& rm -rf /var/lib/apt/lists/* \
&& ln -sf /usr/local/bin/python3.12 /usr/bin/python3 \
&& ln -sf /usr/local/bin/python3.12 /usr/bin/python
Expand Down
16 changes: 8 additions & 8 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ verify_ssl = true
name = "pypi"

[packages]
fastapi = "~=0.116.1"
uvicorn = "~=0.35.0"
litellm = "~=1.76.0"
fastapi = "~=0.117.1"
uvicorn = "~=0.37.0"
litellm = "~=1.77.3"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid litellm 1.77.3 due to known startup OOM

Line [9] pins to LiteLLM 1.77.3, but that release’s own notes flag a Kubernetes startup OOM regression; we should hold at 1.76.x or skip forward once a patched build (e.g., 1.77.4) is validated.
(docs.litellm.ai)

🤖 Prompt for AI Agents
In Pipfile around line 9, the dependency is pinned to litellm ~=1.77.3 which has
a known Kubernetes startup OOM regression; update the Pipfile to use a safe
version (e.g., pin to the last known-good 1.76.x series or wait and pin to
>=1.77.4 once a patched build is validated), then regenerate the lockfile
(pipenv lock or pipenv install) and run CI/tests to verify startup memory
behavior before merging.

falkordb = "~=1.2.0"
psycopg2-binary = "~=2.9.9"
pymysql = "~=1.1.0"
authlib = "~=1.6.2"
authlib = "~=1.6.4"
itsdangerous = "~=2.2.0"
jsonschema = "~=4.25.0"
tqdm = "~=4.67.1"
Expand All @@ -20,11 +20,11 @@ fastapi-mcp = "~=0.4.0"
graphiti-core = {ref = "staging", git = "git+https://github.com/FalkorDB/graphiti.git"}

[dev-packages]
pytest = "~=8.4.1"
pytest = "~=8.4.2"
pylint = "~=3.3.4"
playwright = "~=1.54.0"
pytest-playwright = "~=0.7.0"
pytest-asyncio = "~=1.1.0"
playwright = "~=1.55.0"
pytest-playwright = "~=0.7.1"
pytest-asyncio = "~=1.2.0"

[requires]
python_version = "3.11"
868 changes: 492 additions & 376 deletions Pipfile.lock

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions api/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

"""
Core module for QueryWeaver.

This module provides the core functionality for QueryWeaver including
error handling, database schema loading, and text-to-SQL processing.
"""

from .errors import InternalError, GraphNotFoundError, InvalidArgumentError
from .schema_loader import load_database, list_databases
from .text2sql import MESSAGE_DELIMITER

__all__ = [
"InternalError",
"GraphNotFoundError",
"InvalidArgumentError",
"load_database",
"list_databases",
"MESSAGE_DELIMITER",
]
13 changes: 13 additions & 0 deletions api/core/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""Custom exceptions for the text2sql API."""

# Interal Error Exception
class InternalError(Exception):
"""Custom exception for internal errors."""

# Graph not found Exception
class GraphNotFoundError(Exception):
"""Custom exception for graph not found errors."""

# Wrong argument Exception
class InvalidArgumentError(Exception):
"""Custom exception for invalid argument errors."""
163 changes: 163 additions & 0 deletions api/core/schema_loader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
"""Database connection routes for the text2sql API."""

import logging
import json
import time
from typing import AsyncGenerator

from pydantic import BaseModel

from api.extensions import db

from api.core.errors import InvalidArgumentError
from api.loaders.base_loader import BaseLoader
from api.loaders.postgres_loader import PostgresLoader
from api.loaders.mysql_loader import MySQLLoader

# Use the same delimiter as in the JavaScript frontend for streaming chunks
MESSAGE_DELIMITER = "|||FALKORDB_MESSAGE_BOUNDARY|||"


class DatabaseConnectionRequest(BaseModel):
"""Database connection request model.

Args:
BaseModel (_type_): _description_
"""

url: str

def _step_start(steps_counter: int) -> dict[str, str]:
"""Yield the starting step message."""
return {
"type": "reasoning_step",
"message": f"Step {steps_counter}: Starting database connection",
}

def _step_detect_db_type(steps_counter: int, url: str) -> tuple[type[BaseLoader], dict[str, str]]:
"""Yield the database type detection step message."""
db_type = None
loader: type[BaseLoader] = BaseLoader # type: ignore
if url.startswith("postgres://") or url.startswith("postgresql://"):
db_type = "postgresql"
loader = PostgresLoader
elif url.startswith("mysql://"):
db_type = "mysql"
loader = MySQLLoader
else:
raise InvalidArgumentError("Invalid database URL format")

return loader, {
"type": "reasoning_step",
"message": f"Step {steps_counter}: Detected database type: {db_type}. "
"Attempting to load schema...",
}


async def _step_attempt_load(
steps_counter: int, loader: type[BaseLoader], user_id: str, url: str
) -> AsyncGenerator[dict[str, str | bool], None]:
"""Yield the attempt to load schema step message."""
success, result = [False, ""]
try:
load_start = time.perf_counter()
async for progress in loader.load(user_id, url):
success, result = progress
if success:
steps_counter += 1
yield {
"type": "reasoning_step",
"message": f"Step {steps_counter}: {result}",
}
else:
break

load_elapsed = time.perf_counter() - load_start
logging.info("Database load attempt finished in %.2f seconds", load_elapsed)

if success:
yield {
"type": "final_result",
"success": True,
"message": "Database connected and schema loaded successfully",
}
else:
# Don't stream the full internal result; give higher-level error
logging.error("Database loader failed: %s", str(result)) # nosemgrep
yield {"type": "error", "message": "Failed to load database schema"}
except Exception as e: # pylint: disable=broad-exception-caught
logging.exception("Error while loading database schema: %s", str(e))
yield {"type": "error", "message": "Error connecting to database"}


def _step_result(result) -> str:
"""Yield the final result message."""
return json.dumps(result) + MESSAGE_DELIMITER


async def load_database(url: str, user_id: str):
"""
Accepts a JSON payload with a database URL and attempts to connect.
Supports both PostgreSQL and MySQL databases.
Streams progress steps as a sequence of JSON messages separated by MESSAGE_DELIMITER.
"""

# Validate URL format
if len(url.strip()) == 0:
raise InvalidArgumentError("Invalid URL format")

Comment thread
coderabbitai[bot] marked this conversation as resolved.
async def generate():
overall_start = time.perf_counter()
steps_counter = 0
try:
# Step 1: Start
steps_counter += 1
result = _step_start(steps_counter)
yield _step_result(result)

# Step 2: Determine type
steps_counter += 1
loader, result = _step_detect_db_type(steps_counter, url)
yield _step_result(result)

# Step 3: Attempt to load schema using the loader
async for progress in _step_attempt_load(
steps_counter, loader, user_id, url
):
yield _step_result(progress)

except InvalidArgumentError as ia:
yield _step_result({"type": "error", "message": str(ia)})
except Exception as e: # pylint: disable=broad-exception-caught
logging.exception("Unexpected error in connect_database stream: %s", str(e))
yield _step_result({"type": "error", "message": "Internal server error"})
finally:
overall_elapsed = time.perf_counter() - overall_start
logging.info(
"connect_database processing completed - Total time: %.2f seconds",
overall_elapsed,
)

return generate()


async def list_databases(user_id: str, general_prefix: str) -> list[str]:
"""
This route is used to list all the graphs (databases names) that are available in the database.
"""
user_graphs = await db.list_graphs()

# Only include graphs that start with user_id + '_', and strip the prefix
filtered_graphs = [
graph[len(f"{user_id}_") :]
for graph in user_graphs
if graph.startswith(f"{user_id}_")
]

if general_prefix:
demo_graphs = [
graph for graph in user_graphs if graph.startswith(general_prefix)
]
filtered_graphs = filtered_graphs + demo_graphs

return filtered_graphs
Loading
Loading