graphiti-core 0.20.3__tar.gz → 0.21.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphiti-core might be problematic. Click here for more details.
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/workflows/claude-code-review.yml +3 -0
- graphiti_core-0.21.0/.github/workflows/daily_issue_maintenance.yml +123 -0
- graphiti_core-0.21.0/.github/workflows/issue-triage.yml +141 -0
- graphiti_core-0.21.0/AGENTS.md +21 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/Makefile +2 -2
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/PKG-INFO +7 -1
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/docker-compose.test.yml +1 -1
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/driver/driver.py +28 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/driver/falkordb_driver.py +112 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/driver/kuzu_driver.py +1 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/driver/neo4j_driver.py +10 -2
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/driver/neptune_driver.py +4 -6
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/edges.py +67 -7
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/embedder/client.py +2 -1
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/graph_queries.py +35 -6
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/graphiti.py +36 -24
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/graphiti_types.py +0 -1
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/helpers.py +2 -2
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/llm_client/client.py +19 -4
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/llm_client/gemini_client.py +4 -2
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/llm_client/openai_base_client.py +3 -2
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/llm_client/openai_generic_client.py +3 -2
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/models/edges/edge_db_queries.py +36 -16
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/models/nodes/node_db_queries.py +30 -10
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/nodes.py +126 -25
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/prompts/dedupe_edges.py +40 -29
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/prompts/dedupe_nodes.py +51 -34
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/prompts/eval.py +3 -3
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/prompts/extract_edges.py +17 -9
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/prompts/extract_nodes.py +10 -9
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/prompts/prompt_helpers.py +3 -3
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/prompts/summarize_nodes.py +5 -5
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/search/search_filters.py +53 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/search/search_helpers.py +5 -7
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/search/search_utils.py +227 -57
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/utils/bulk_utils.py +168 -69
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/utils/maintenance/community_operations.py +8 -20
- graphiti_core-0.21.0/graphiti_core/utils/maintenance/dedup_helpers.py +262 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/utils/maintenance/edge_operations.py +187 -50
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/utils/maintenance/graph_data_operations.py +9 -5
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/utils/maintenance/node_operations.py +244 -88
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/utils/maintenance/temporal_operations.py +0 -4
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/pyproject.toml +5 -1
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/signatures/version1/cla.json +32 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/test_edge_int.py +1 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/test_node_int.py +2 -0
- graphiti_core-0.21.0/tests/utils/maintenance/test_bulk_utils.py +328 -0
- graphiti_core-0.21.0/tests/utils/maintenance/test_edge_operations.py +647 -0
- graphiti_core-0.21.0/tests/utils/maintenance/test_node_operations.py +651 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/uv.lock +15 -3
- graphiti_core-0.20.3/poetry.lock +0 -5627
- graphiti_core-0.20.3/tests/utils/maintenance/test_edge_operations.py +0 -94
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.env.example +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/dependabot.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/pull_request_template.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/secret_scanning.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/workflows/ai-moderator.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/workflows/cla.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/workflows/claude.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/workflows/codeql.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/workflows/lint.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/workflows/mcp-server-docker.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/workflows/release-graphiti-core.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/workflows/typecheck.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.github/workflows/unit_tests.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/.gitignore +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/CLAUDE.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/CODE_OF_CONDUCT.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/CONTRIBUTING.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/Dockerfile +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/LICENSE +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/README.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/SECURITY.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/Zep-CLA.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/conftest.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/depot.json +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/docker-compose.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/ellipsis.yaml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/data/manybirds_products.json +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/ecommerce/runner.ipynb +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/ecommerce/runner.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/langgraph-agent/agent.ipynb +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/langgraph-agent/tinybirds-jess.png +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/podcast/podcast_runner.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/podcast/podcast_transcript.txt +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/podcast/transcript_parser.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/quickstart/README.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/quickstart/quickstart_falkordb.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/quickstart/quickstart_neo4j.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/quickstart/quickstart_neptune.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/quickstart/requirements.txt +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/wizard_of_oz/parser.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/wizard_of_oz/runner.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/examples/wizard_of_oz/woo.txt +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/cross_encoder/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/cross_encoder/bge_reranker_client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/cross_encoder/client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/cross_encoder/gemini_reranker_client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/cross_encoder/openai_reranker_client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/driver/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/embedder/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/embedder/azure_openai.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/embedder/gemini.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/embedder/openai.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/embedder/voyage.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/errors.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/llm_client/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/llm_client/anthropic_client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/llm_client/azure_openai_client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/llm_client/config.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/llm_client/errors.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/llm_client/groq_client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/llm_client/openai_client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/llm_client/utils.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/migrations/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/models/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/models/edges/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/models/nodes/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/prompts/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/prompts/extract_edge_dates.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/prompts/invalidate_edges.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/prompts/lib.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/prompts/models.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/py.typed +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/search/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/search/search.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/search/search_config.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/search/search_config_recipes.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/telemetry/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/telemetry/telemetry.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/utils/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/utils/datetime_utils.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/utils/maintenance/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/utils/maintenance/utils.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/graphiti_core/utils/ontology_utils/entity_types_utils.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/images/arxiv-screenshot.png +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/images/graphiti-graph-intro.gif +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/images/graphiti-intro-slides-stock-2.gif +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/images/simple_graph.svg +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/mcp_server/.env.example +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/mcp_server/.python-version +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/mcp_server/Dockerfile +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/mcp_server/README.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/mcp_server/cursor_rules.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/mcp_server/docker-compose.yml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/mcp_server/graphiti_mcp_server.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/mcp_server/mcp_config_sse_example.json +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/mcp_server/mcp_config_stdio_example.json +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/mcp_server/pyproject.toml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/mcp_server/uv.lock +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/py.typed +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/pytest.ini +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/.env.example +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/Makefile +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/README.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/graph_service/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/graph_service/config.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/graph_service/dto/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/graph_service/dto/common.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/graph_service/dto/ingest.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/graph_service/dto/retrieve.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/graph_service/main.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/graph_service/routers/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/graph_service/routers/ingest.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/graph_service/routers/retrieve.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/graph_service/zep_graphiti.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/pyproject.toml +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/server/uv.lock +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/cross_encoder/test_bge_reranker_client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/cross_encoder/test_gemini_reranker_client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/driver/__init__.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/driver/test_falkordb_driver.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/embedder/embedder_fixtures.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/embedder/test_gemini.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/embedder/test_openai.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/embedder/test_voyage.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/evals/data/longmemeval_data/README.md +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/evals/data/longmemeval_data/longmemeval_oracle.json +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/evals/eval_cli.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/evals/eval_e2e_graph_building.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/evals/pytest.ini +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/evals/utils.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/helpers_test.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/llm_client/test_anthropic_client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/llm_client/test_anthropic_client_int.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/llm_client/test_client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/llm_client/test_errors.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/llm_client/test_gemini_client.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/test_entity_exclusion_int.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/test_graphiti_int.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/test_graphiti_mock.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/utils/maintenance/test_temporal_operations_int.py +0 -0
- {graphiti_core-0.20.3 → graphiti_core-0.21.0}/tests/utils/search/search_utils_test.py +0 -0
|
@@ -29,6 +29,8 @@ jobs:
|
|
|
29
29
|
|
|
30
30
|
Please review this pull request.
|
|
31
31
|
|
|
32
|
+
IMPORTANT: Your role is to critically review code. You must not provide POSITIVE feedback on code, this only adds noise to the review process.
|
|
33
|
+
|
|
32
34
|
Note: The PR branch is already checked out in the current working directory.
|
|
33
35
|
|
|
34
36
|
Focus on:
|
|
@@ -48,3 +50,4 @@ jobs:
|
|
|
48
50
|
|
|
49
51
|
claude_args: |
|
|
50
52
|
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*), Bash(gh pr diff:*), Bash(gh pr view:*)"
|
|
53
|
+
--model claude-sonnet-4-5-20250929
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
name: Daily Issue Maintenance
|
|
2
|
+
on:
|
|
3
|
+
schedule:
|
|
4
|
+
- cron: "0 0 * * *" # Every day at midnight
|
|
5
|
+
workflow_dispatch: # Manual trigger option
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
find-legacy-duplicates:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
if: github.event_name == 'workflow_dispatch'
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
issues: write
|
|
14
|
+
id-token: write
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 1
|
|
19
|
+
|
|
20
|
+
- uses: anthropics/claude-code-action@v1
|
|
21
|
+
with:
|
|
22
|
+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
23
|
+
prompt: |
|
|
24
|
+
REPO: ${{ github.repository }}
|
|
25
|
+
|
|
26
|
+
Find potential duplicate issues in the repository:
|
|
27
|
+
|
|
28
|
+
1. Use `gh issue list --state open --limit 1000 --json number,title,body,createdAt` to get all open issues
|
|
29
|
+
2. For each issue, search for potential duplicates using `gh search issues` with keywords from the title and body
|
|
30
|
+
3. Compare issues to identify true duplicates using these criteria:
|
|
31
|
+
- Same bug or error being reported
|
|
32
|
+
- Same feature request (even if worded differently)
|
|
33
|
+
- Same question being asked
|
|
34
|
+
- Issues describing the same root problem
|
|
35
|
+
|
|
36
|
+
For each duplicate found:
|
|
37
|
+
- Add a comment linking to the original issue
|
|
38
|
+
- Apply the "duplicate" label using `gh issue edit`
|
|
39
|
+
- Be polite and explain why it's a duplicate
|
|
40
|
+
|
|
41
|
+
Focus on finding true duplicates, not just similar issues.
|
|
42
|
+
|
|
43
|
+
claude_args: |
|
|
44
|
+
--allowedTools "Bash(gh issue:*),Bash(gh search:*)"
|
|
45
|
+
--model claude-sonnet-4-5-20250929
|
|
46
|
+
|
|
47
|
+
check-stale-issues:
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
if: github.event_name == 'schedule'
|
|
50
|
+
permissions:
|
|
51
|
+
contents: read
|
|
52
|
+
issues: write
|
|
53
|
+
id-token: write
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/checkout@v4
|
|
56
|
+
with:
|
|
57
|
+
fetch-depth: 1
|
|
58
|
+
|
|
59
|
+
- uses: anthropics/claude-code-action@v1
|
|
60
|
+
with:
|
|
61
|
+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
62
|
+
prompt: |
|
|
63
|
+
REPO: ${{ github.repository }}
|
|
64
|
+
|
|
65
|
+
Review stale issues and request confirmation:
|
|
66
|
+
|
|
67
|
+
1. Use `gh issue list --state open --limit 1000 --json number,title,updatedAt,comments` to get all open issues
|
|
68
|
+
2. Identify issues that are:
|
|
69
|
+
- Older than 60 days (based on updatedAt)
|
|
70
|
+
- Have no comments with "stale-check" label
|
|
71
|
+
- Are not labeled as "enhancement" or "documentation"
|
|
72
|
+
3. For each stale issue:
|
|
73
|
+
- Add a polite comment asking the issue originator if this is still relevant
|
|
74
|
+
- Apply a "stale-check" label to track that we've asked
|
|
75
|
+
- Use format: "@{author} Is this still an issue? Please confirm within 14 days or this issue will be closed."
|
|
76
|
+
|
|
77
|
+
Use:
|
|
78
|
+
- `gh issue view` to check issue details and labels
|
|
79
|
+
- `gh issue comment` to add comments
|
|
80
|
+
- `gh issue edit` to add the "stale-check" label
|
|
81
|
+
|
|
82
|
+
claude_args: |
|
|
83
|
+
--allowedTools "Bash(gh issue:*)"
|
|
84
|
+
--model claude-sonnet-4-5-20250929
|
|
85
|
+
|
|
86
|
+
close-unconfirmed-issues:
|
|
87
|
+
runs-on: ubuntu-latest
|
|
88
|
+
if: github.event_name == 'schedule'
|
|
89
|
+
needs: check-stale-issues
|
|
90
|
+
permissions:
|
|
91
|
+
contents: read
|
|
92
|
+
issues: write
|
|
93
|
+
id-token: write
|
|
94
|
+
steps:
|
|
95
|
+
- uses: actions/checkout@v4
|
|
96
|
+
with:
|
|
97
|
+
fetch-depth: 1
|
|
98
|
+
|
|
99
|
+
- uses: anthropics/claude-code-action@v1
|
|
100
|
+
with:
|
|
101
|
+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
102
|
+
prompt: |
|
|
103
|
+
REPO: ${{ github.repository }}
|
|
104
|
+
|
|
105
|
+
Close unconfirmed stale issues:
|
|
106
|
+
|
|
107
|
+
1. Use `gh issue list --state open --label "stale-check" --limit 1000 --json number,title,comments,updatedAt` to get issues with stale-check label
|
|
108
|
+
2. For each issue, check if:
|
|
109
|
+
- The "stale-check" comment was added 14+ days ago
|
|
110
|
+
- There has been no response from the issue author or activity since the comment
|
|
111
|
+
3. For issues meeting the criteria:
|
|
112
|
+
- Add a polite closing comment
|
|
113
|
+
- Close the issue using `gh issue close`
|
|
114
|
+
- Use format: "Closing due to inactivity. Feel free to reopen if this is still relevant."
|
|
115
|
+
|
|
116
|
+
Use:
|
|
117
|
+
- `gh issue view` to check issue comments and activity
|
|
118
|
+
- `gh issue comment` to add closing comment
|
|
119
|
+
- `gh issue close` to close the issue
|
|
120
|
+
|
|
121
|
+
claude_args: |
|
|
122
|
+
--allowedTools "Bash(gh issue:*)"
|
|
123
|
+
--model claude-sonnet-4-5-20250929
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
name: Issue Triage and Deduplication
|
|
2
|
+
on:
|
|
3
|
+
issues:
|
|
4
|
+
types: [opened]
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
triage:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
timeout-minutes: 10
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
issues: write
|
|
13
|
+
id-token: write
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout repository
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
with:
|
|
19
|
+
fetch-depth: 1
|
|
20
|
+
|
|
21
|
+
- name: Run Claude Code for Issue Triage
|
|
22
|
+
uses: anthropics/claude-code-action@v1
|
|
23
|
+
with:
|
|
24
|
+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
25
|
+
allowed_non_write_users: "*"
|
|
26
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
27
|
+
prompt: |
|
|
28
|
+
You're an issue triage assistant for GitHub issues. Your task is to analyze the issue and select appropriate labels from the provided list.
|
|
29
|
+
|
|
30
|
+
IMPORTANT: Don't post any comments or messages to the issue. Your only action should be to apply labels. DO NOT check for duplicates - that's handled by a separate job.
|
|
31
|
+
|
|
32
|
+
Issue Information:
|
|
33
|
+
- REPO: ${{ github.repository }}
|
|
34
|
+
- ISSUE_NUMBER: ${{ github.event.issue.number }}
|
|
35
|
+
|
|
36
|
+
TASK OVERVIEW:
|
|
37
|
+
|
|
38
|
+
1. First, fetch the list of labels available in this repository by running: `gh label list`. Run exactly this command with nothing else.
|
|
39
|
+
|
|
40
|
+
2. Next, use gh commands to get context about the issue:
|
|
41
|
+
- Use `gh issue view ${{ github.event.issue.number }}` to retrieve the current issue's details
|
|
42
|
+
- Use `gh search issues` to find similar issues that might provide context for proper categorization
|
|
43
|
+
- You have access to these Bash commands:
|
|
44
|
+
- Bash(gh label list:*) - to get available labels
|
|
45
|
+
- Bash(gh issue view:*) - to view issue details
|
|
46
|
+
- Bash(gh issue edit:*) - to apply labels to the issue
|
|
47
|
+
- Bash(gh search:*) - to search for similar issues
|
|
48
|
+
|
|
49
|
+
3. Analyze the issue content, considering:
|
|
50
|
+
- The issue title and description
|
|
51
|
+
- The type of issue (bug report, feature request, question, etc.)
|
|
52
|
+
- Technical areas mentioned
|
|
53
|
+
- Database mentions (neo4j, falkordb, neptune, etc.)
|
|
54
|
+
- LLM providers mentioned (openai, anthropic, gemini, groq, etc.)
|
|
55
|
+
- Components affected (embeddings, search, prompts, server, mcp, etc.)
|
|
56
|
+
|
|
57
|
+
4. Select appropriate labels from the available labels list:
|
|
58
|
+
- Choose labels that accurately reflect the issue's nature
|
|
59
|
+
- Be specific but comprehensive
|
|
60
|
+
- Add database-specific labels if mentioned: neo4j, falkordb, neptune
|
|
61
|
+
- Add component labels if applicable
|
|
62
|
+
- DO NOT add priority labels (P1, P2, P3)
|
|
63
|
+
- DO NOT add duplicate label - that's handled by the deduplication job
|
|
64
|
+
|
|
65
|
+
5. Apply the selected labels:
|
|
66
|
+
- Use `gh issue edit ${{ github.event.issue.number }} --add-label "label1,label2,label3"` to apply your selected labels
|
|
67
|
+
- DO NOT post any comments explaining your decision
|
|
68
|
+
- DO NOT communicate directly with users
|
|
69
|
+
- If no labels are clearly applicable, do not apply any labels
|
|
70
|
+
|
|
71
|
+
IMPORTANT GUIDELINES:
|
|
72
|
+
- Be thorough in your analysis
|
|
73
|
+
- Only select labels from the provided list
|
|
74
|
+
- DO NOT post any comments to the issue
|
|
75
|
+
- Your ONLY action should be to apply labels using gh issue edit
|
|
76
|
+
- It's okay to not add any labels if none are clearly applicable
|
|
77
|
+
- DO NOT check for duplicates
|
|
78
|
+
|
|
79
|
+
claude_args: |
|
|
80
|
+
--allowedTools "Bash(gh label list:*),Bash(gh issue view:*),Bash(gh issue edit:*),Bash(gh search:*)"
|
|
81
|
+
--model claude-sonnet-4-5-20250929
|
|
82
|
+
|
|
83
|
+
deduplicate:
|
|
84
|
+
runs-on: ubuntu-latest
|
|
85
|
+
timeout-minutes: 10
|
|
86
|
+
needs: triage
|
|
87
|
+
permissions:
|
|
88
|
+
contents: read
|
|
89
|
+
issues: write
|
|
90
|
+
id-token: write
|
|
91
|
+
|
|
92
|
+
steps:
|
|
93
|
+
- name: Checkout repository
|
|
94
|
+
uses: actions/checkout@v4
|
|
95
|
+
with:
|
|
96
|
+
fetch-depth: 1
|
|
97
|
+
|
|
98
|
+
- name: Check for duplicate issues
|
|
99
|
+
uses: anthropics/claude-code-action@v1
|
|
100
|
+
with:
|
|
101
|
+
allowed_non_write_users: "*"
|
|
102
|
+
prompt: |
|
|
103
|
+
Analyze this new issue and check if it's a duplicate of existing issues in the repository.
|
|
104
|
+
|
|
105
|
+
Issue: #${{ github.event.issue.number }}
|
|
106
|
+
Repository: ${{ github.repository }}
|
|
107
|
+
|
|
108
|
+
Your task:
|
|
109
|
+
1. Use mcp__github__get_issue to get details of the current issue (#${{ github.event.issue.number }})
|
|
110
|
+
2. Search for similar existing OPEN issues using mcp__github__search_issues with relevant keywords from the issue title and body
|
|
111
|
+
3. Compare the new issue with existing ones to identify potential duplicates
|
|
112
|
+
|
|
113
|
+
Criteria for duplicates:
|
|
114
|
+
- Same bug or error being reported
|
|
115
|
+
- Same feature request (even if worded differently)
|
|
116
|
+
- Same question being asked
|
|
117
|
+
- Issues describing the same root problem
|
|
118
|
+
|
|
119
|
+
If you find duplicates:
|
|
120
|
+
- Add a comment on the new issue linking to the original issue(s)
|
|
121
|
+
- Apply the "duplicate" label to the new issue
|
|
122
|
+
- Be polite and explain why it's a duplicate
|
|
123
|
+
- Suggest the user follow the original issue for updates
|
|
124
|
+
|
|
125
|
+
If it's NOT a duplicate:
|
|
126
|
+
- Don't add any comments
|
|
127
|
+
- Don't modify labels
|
|
128
|
+
|
|
129
|
+
Use these tools:
|
|
130
|
+
- mcp__github__get_issue: Get issue details
|
|
131
|
+
- mcp__github__search_issues: Search for similar issues (use state:open)
|
|
132
|
+
- mcp__github__list_issues: List recent issues if needed
|
|
133
|
+
- mcp__github__create_issue_comment: Add a comment if duplicate found
|
|
134
|
+
- mcp__github__update_issue: Add "duplicate" label
|
|
135
|
+
|
|
136
|
+
Be thorough but efficient. Focus on finding true duplicates, not just similar issues.
|
|
137
|
+
|
|
138
|
+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
139
|
+
claude_args: |
|
|
140
|
+
--allowedTools "mcp__github__get_issue,mcp__github__search_issues,mcp__github__list_issues,mcp__github__create_issue_comment,mcp__github__update_issue,mcp__github__get_issue_comments"
|
|
141
|
+
--model claude-sonnet-4-5-20250929
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Repository Guidelines
|
|
2
|
+
|
|
3
|
+
## Project Structure & Module Organization
|
|
4
|
+
Graphiti's core library lives under `graphiti_core/`, split into domain modules such as `nodes.py`, `edges.py`, `models/`, and `search/` for retrieval pipelines. Service adapters and API glue reside in `server/graph_service/`, while the MCP integration lives in `mcp_server/`. Shared assets and collateral sit in `images/` and `examples/`. Tests cover the package via `tests/`, with configuration in `conftest.py`, `pytest.ini`, and Docker compose files for optional services. Tooling manifests live at the repo root, including `pyproject.toml`, `Makefile`, and deployment compose files.
|
|
5
|
+
|
|
6
|
+
## Build, Test, and Development Commands
|
|
7
|
+
- `uv sync --extra dev`: install the dev environment declared in `pyproject.toml`.
|
|
8
|
+
- `make format`: run `ruff` to sort imports and apply the canonical formatter.
|
|
9
|
+
- `make lint`: execute `ruff` plus `pyright` type checks against `graphiti_core`.
|
|
10
|
+
- `make test`: run the full `pytest` suite (`uv run pytest`).
|
|
11
|
+
- `uv run pytest tests/path/test_file.py`: target a specific module or test selection.
|
|
12
|
+
- `docker-compose -f docker-compose.test.yml up`: provision local graph/search dependencies for integration flows.
|
|
13
|
+
|
|
14
|
+
## Coding Style & Naming Conventions
|
|
15
|
+
Python code uses 4-space indentation, 100-character lines, and prefers single quotes as configured in `pyproject.toml`. Modules, files, and functions stay snake_case; Pydantic models in `graphiti_core/models` use PascalCase with explicit type hints. Keep side-effectful code inside drivers or adapters (`graphiti_core/driver`, `graphiti_core/utils`) and rely on pure helpers elsewhere. Run `make format` before committing to normalize imports and docstring formatting.
|
|
16
|
+
|
|
17
|
+
## Testing Guidelines
|
|
18
|
+
Author tests alongside features under `tests/`, naming files `test_<feature>.py` and functions `test_<behavior>`. Use `@pytest.mark.integration` for database-reliant scenarios so CI can gate them. Reproduce regressions with a failing test first and validate fixes via `uv run pytest -k "pattern"`. Start required backing services through `docker-compose.test.yml` when running integration suites locally.
|
|
19
|
+
|
|
20
|
+
## Commit & Pull Request Guidelines
|
|
21
|
+
Commits use an imperative, present-tense summary (for example, `add async cache invalidation`) optionally suffixed with the PR number as seen in history (`(#927)`). Squash fixups and keep unrelated changes isolated. Pull requests should include: a concise description, linked tracking issue, notes about schema or API impacts, and screenshots or logs when behavior changes. Confirm `make lint` and `make test` pass locally, and update docs or examples when public interfaces shift.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graphiti-core
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.21.0
|
|
4
4
|
Summary: A temporal graph building library
|
|
5
5
|
Project-URL: Homepage, https://help.getzep.com/graphiti/graphiti/overview
|
|
6
6
|
Project-URL: Repository, https://github.com/getzep/graphiti
|
|
@@ -20,6 +20,7 @@ Provides-Extra: anthropic
|
|
|
20
20
|
Requires-Dist: anthropic>=0.49.0; extra == 'anthropic'
|
|
21
21
|
Provides-Extra: dev
|
|
22
22
|
Requires-Dist: anthropic>=0.49.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: boto3>=1.39.16; extra == 'dev'
|
|
23
24
|
Requires-Dist: diskcache-stubs>=5.6.3.6.20240818; extra == 'dev'
|
|
24
25
|
Requires-Dist: falkordb<2.0.0,>=1.1.2; extra == 'dev'
|
|
25
26
|
Requires-Dist: google-genai>=1.8.0; extra == 'dev'
|
|
@@ -28,9 +29,11 @@ Requires-Dist: ipykernel>=6.29.5; extra == 'dev'
|
|
|
28
29
|
Requires-Dist: jupyterlab>=4.2.4; extra == 'dev'
|
|
29
30
|
Requires-Dist: kuzu>=0.11.2; extra == 'dev'
|
|
30
31
|
Requires-Dist: langchain-anthropic>=0.2.4; extra == 'dev'
|
|
32
|
+
Requires-Dist: langchain-aws>=0.2.29; extra == 'dev'
|
|
31
33
|
Requires-Dist: langchain-openai>=0.2.6; extra == 'dev'
|
|
32
34
|
Requires-Dist: langgraph>=0.2.15; extra == 'dev'
|
|
33
35
|
Requires-Dist: langsmith>=0.1.108; extra == 'dev'
|
|
36
|
+
Requires-Dist: opensearch-py>=3.0.0; extra == 'dev'
|
|
34
37
|
Requires-Dist: pyright>=1.1.404; extra == 'dev'
|
|
35
38
|
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
|
|
36
39
|
Requires-Dist: pytest-xdist>=3.6.1; extra == 'dev'
|
|
@@ -47,6 +50,9 @@ Provides-Extra: groq
|
|
|
47
50
|
Requires-Dist: groq>=0.2.0; extra == 'groq'
|
|
48
51
|
Provides-Extra: kuzu
|
|
49
52
|
Requires-Dist: kuzu>=0.11.2; extra == 'kuzu'
|
|
53
|
+
Provides-Extra: neo4j-opensearch
|
|
54
|
+
Requires-Dist: boto3>=1.39.16; extra == 'neo4j-opensearch'
|
|
55
|
+
Requires-Dist: opensearch-py>=3.0.0; extra == 'neo4j-opensearch'
|
|
50
56
|
Provides-Extra: neptune
|
|
51
57
|
Requires-Dist: boto3>=1.39.16; extra == 'neptune'
|
|
52
58
|
Requires-Dist: langchain-aws>=0.2.29; extra == 'neptune'
|
|
@@ -16,13 +16,25 @@ limitations under the License.
|
|
|
16
16
|
|
|
17
17
|
import copy
|
|
18
18
|
import logging
|
|
19
|
+
import os
|
|
19
20
|
from abc import ABC, abstractmethod
|
|
20
21
|
from collections.abc import Coroutine
|
|
21
22
|
from enum import Enum
|
|
22
23
|
from typing import Any
|
|
23
24
|
|
|
25
|
+
from dotenv import load_dotenv
|
|
26
|
+
|
|
24
27
|
logger = logging.getLogger(__name__)
|
|
25
28
|
|
|
29
|
+
DEFAULT_SIZE = 10
|
|
30
|
+
|
|
31
|
+
load_dotenv()
|
|
32
|
+
|
|
33
|
+
ENTITY_INDEX_NAME = os.environ.get('ENTITY_INDEX_NAME', 'entities')
|
|
34
|
+
EPISODE_INDEX_NAME = os.environ.get('EPISODE_INDEX_NAME', 'episodes')
|
|
35
|
+
COMMUNITY_INDEX_NAME = os.environ.get('COMMUNITY_INDEX_NAME', 'communities')
|
|
36
|
+
ENTITY_EDGE_INDEX_NAME = os.environ.get('ENTITY_EDGE_INDEX_NAME', 'entity_edges')
|
|
37
|
+
|
|
26
38
|
|
|
27
39
|
class GraphProvider(Enum):
|
|
28
40
|
NEO4J = 'neo4j'
|
|
@@ -61,6 +73,7 @@ class GraphDriver(ABC):
|
|
|
61
73
|
'' # Neo4j (default) syntax does not require a prefix for fulltext queries
|
|
62
74
|
)
|
|
63
75
|
_database: str
|
|
76
|
+
aoss_client: Any # type: ignore
|
|
64
77
|
|
|
65
78
|
@abstractmethod
|
|
66
79
|
def execute_query(self, cypher_query_: str, **kwargs: Any) -> Coroutine:
|
|
@@ -87,3 +100,18 @@ class GraphDriver(ABC):
|
|
|
87
100
|
cloned._database = database
|
|
88
101
|
|
|
89
102
|
return cloned
|
|
103
|
+
|
|
104
|
+
def build_fulltext_query(
|
|
105
|
+
self, query: str, group_ids: list[str] | None = None, max_query_length: int = 128
|
|
106
|
+
) -> str:
|
|
107
|
+
"""
|
|
108
|
+
Specific fulltext query builder for database providers.
|
|
109
|
+
Only implemented by providers that need custom fulltext query building.
|
|
110
|
+
"""
|
|
111
|
+
raise NotImplementedError(f'build_fulltext_query not implemented for {self.provider}')
|
|
112
|
+
|
|
113
|
+
async def save_to_aoss(self, name: str, data: list[dict]) -> int:
|
|
114
|
+
return 0
|
|
115
|
+
|
|
116
|
+
async def clear_aoss_indices(self):
|
|
117
|
+
return 1
|
|
@@ -36,6 +36,42 @@ from graphiti_core.utils.datetime_utils import convert_datetimes_to_strings
|
|
|
36
36
|
|
|
37
37
|
logger = logging.getLogger(__name__)
|
|
38
38
|
|
|
39
|
+
STOPWORDS = [
|
|
40
|
+
'a',
|
|
41
|
+
'is',
|
|
42
|
+
'the',
|
|
43
|
+
'an',
|
|
44
|
+
'and',
|
|
45
|
+
'are',
|
|
46
|
+
'as',
|
|
47
|
+
'at',
|
|
48
|
+
'be',
|
|
49
|
+
'but',
|
|
50
|
+
'by',
|
|
51
|
+
'for',
|
|
52
|
+
'if',
|
|
53
|
+
'in',
|
|
54
|
+
'into',
|
|
55
|
+
'it',
|
|
56
|
+
'no',
|
|
57
|
+
'not',
|
|
58
|
+
'of',
|
|
59
|
+
'on',
|
|
60
|
+
'or',
|
|
61
|
+
'such',
|
|
62
|
+
'that',
|
|
63
|
+
'their',
|
|
64
|
+
'then',
|
|
65
|
+
'there',
|
|
66
|
+
'these',
|
|
67
|
+
'they',
|
|
68
|
+
'this',
|
|
69
|
+
'to',
|
|
70
|
+
'was',
|
|
71
|
+
'will',
|
|
72
|
+
'with',
|
|
73
|
+
]
|
|
74
|
+
|
|
39
75
|
|
|
40
76
|
class FalkorDriverSession(GraphDriverSession):
|
|
41
77
|
provider = GraphProvider.FALKORDB
|
|
@@ -74,6 +110,7 @@ class FalkorDriverSession(GraphDriverSession):
|
|
|
74
110
|
|
|
75
111
|
class FalkorDriver(GraphDriver):
|
|
76
112
|
provider = GraphProvider.FALKORDB
|
|
113
|
+
aoss_client: None = None
|
|
77
114
|
|
|
78
115
|
def __init__(
|
|
79
116
|
self,
|
|
@@ -166,3 +203,78 @@ class FalkorDriver(GraphDriver):
|
|
|
166
203
|
cloned = FalkorDriver(falkor_db=self.client, database=database)
|
|
167
204
|
|
|
168
205
|
return cloned
|
|
206
|
+
|
|
207
|
+
def sanitize(self, query: str) -> str:
|
|
208
|
+
"""
|
|
209
|
+
Replace FalkorDB special characters with whitespace.
|
|
210
|
+
Based on FalkorDB tokenization rules: ,.<>{}[]"':;!@#$%^&*()-+=~
|
|
211
|
+
"""
|
|
212
|
+
# FalkorDB separator characters that break text into tokens
|
|
213
|
+
separator_map = str.maketrans(
|
|
214
|
+
{
|
|
215
|
+
',': ' ',
|
|
216
|
+
'.': ' ',
|
|
217
|
+
'<': ' ',
|
|
218
|
+
'>': ' ',
|
|
219
|
+
'{': ' ',
|
|
220
|
+
'}': ' ',
|
|
221
|
+
'[': ' ',
|
|
222
|
+
']': ' ',
|
|
223
|
+
'"': ' ',
|
|
224
|
+
"'": ' ',
|
|
225
|
+
':': ' ',
|
|
226
|
+
';': ' ',
|
|
227
|
+
'!': ' ',
|
|
228
|
+
'@': ' ',
|
|
229
|
+
'#': ' ',
|
|
230
|
+
'$': ' ',
|
|
231
|
+
'%': ' ',
|
|
232
|
+
'^': ' ',
|
|
233
|
+
'&': ' ',
|
|
234
|
+
'*': ' ',
|
|
235
|
+
'(': ' ',
|
|
236
|
+
')': ' ',
|
|
237
|
+
'-': ' ',
|
|
238
|
+
'+': ' ',
|
|
239
|
+
'=': ' ',
|
|
240
|
+
'~': ' ',
|
|
241
|
+
'?': ' ',
|
|
242
|
+
}
|
|
243
|
+
)
|
|
244
|
+
sanitized = query.translate(separator_map)
|
|
245
|
+
# Clean up multiple spaces
|
|
246
|
+
sanitized = ' '.join(sanitized.split())
|
|
247
|
+
return sanitized
|
|
248
|
+
|
|
249
|
+
def build_fulltext_query(
|
|
250
|
+
self, query: str, group_ids: list[str] | None = None, max_query_length: int = 128
|
|
251
|
+
) -> str:
|
|
252
|
+
"""
|
|
253
|
+
Build a fulltext query string for FalkorDB using RedisSearch syntax.
|
|
254
|
+
FalkorDB uses RedisSearch-like syntax where:
|
|
255
|
+
- Field queries use @ prefix: @field:value
|
|
256
|
+
- Multiple values for same field: (@field:value1|value2)
|
|
257
|
+
- Text search doesn't need @ prefix for content fields
|
|
258
|
+
- AND is implicit with space: (@group_id:value) (text)
|
|
259
|
+
- OR uses pipe within parentheses: (@group_id:value1|value2)
|
|
260
|
+
"""
|
|
261
|
+
if group_ids is None or len(group_ids) == 0:
|
|
262
|
+
group_filter = ''
|
|
263
|
+
else:
|
|
264
|
+
group_values = '|'.join(group_ids)
|
|
265
|
+
group_filter = f'(@group_id:{group_values})'
|
|
266
|
+
|
|
267
|
+
sanitized_query = self.sanitize(query)
|
|
268
|
+
|
|
269
|
+
# Remove stopwords from the sanitized query
|
|
270
|
+
query_words = sanitized_query.split()
|
|
271
|
+
filtered_words = [word for word in query_words if word.lower() not in STOPWORDS]
|
|
272
|
+
sanitized_query = ' | '.join(filtered_words)
|
|
273
|
+
|
|
274
|
+
# If the query is too long return no query
|
|
275
|
+
if len(sanitized_query.split(' ')) + len(group_ids or '') >= max_query_length:
|
|
276
|
+
return ''
|
|
277
|
+
|
|
278
|
+
full_query = group_filter + ' (' + sanitized_query + ')'
|
|
279
|
+
|
|
280
|
+
return full_query
|
|
@@ -29,7 +29,13 @@ logger = logging.getLogger(__name__)
|
|
|
29
29
|
class Neo4jDriver(GraphDriver):
|
|
30
30
|
provider = GraphProvider.NEO4J
|
|
31
31
|
|
|
32
|
-
def __init__(
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
uri: str,
|
|
35
|
+
user: str | None,
|
|
36
|
+
password: str | None,
|
|
37
|
+
database: str = 'neo4j',
|
|
38
|
+
):
|
|
33
39
|
super().__init__()
|
|
34
40
|
self.client = AsyncGraphDatabase.driver(
|
|
35
41
|
uri=uri,
|
|
@@ -37,6 +43,8 @@ class Neo4jDriver(GraphDriver):
|
|
|
37
43
|
)
|
|
38
44
|
self._database = database
|
|
39
45
|
|
|
46
|
+
self.aoss_client = None
|
|
47
|
+
|
|
40
48
|
async def execute_query(self, cypher_query_: LiteralString, **kwargs: Any) -> EagerResult:
|
|
41
49
|
# Check if database_ is provided in kwargs.
|
|
42
50
|
# If not populated, set the value to retain backwards compatibility
|
|
@@ -60,7 +68,7 @@ class Neo4jDriver(GraphDriver):
|
|
|
60
68
|
async def close(self) -> None:
|
|
61
69
|
return await self.client.close()
|
|
62
70
|
|
|
63
|
-
def delete_all_indexes(self) -> Coroutine
|
|
71
|
+
def delete_all_indexes(self) -> Coroutine:
|
|
64
72
|
return self.client.execute_query(
|
|
65
73
|
'CALL db.indexes() YIELD name DROP INDEX name',
|
|
66
74
|
)
|
|
@@ -257,15 +257,13 @@ class NeptuneDriver(GraphDriver):
|
|
|
257
257
|
if name.lower() == index['index_name']:
|
|
258
258
|
to_index = []
|
|
259
259
|
for d in data:
|
|
260
|
-
item = {'_index': name}
|
|
260
|
+
item = {'_index': name, '_id': d['uuid']}
|
|
261
261
|
for p in index['body']['mappings']['properties']:
|
|
262
|
-
|
|
262
|
+
if p in d:
|
|
263
|
+
item[p] = d[p]
|
|
263
264
|
to_index.append(item)
|
|
264
265
|
success, failed = helpers.bulk(self.aoss_client, to_index, stats_only=True)
|
|
265
|
-
|
|
266
|
-
return success
|
|
267
|
-
else:
|
|
268
|
-
return 0
|
|
266
|
+
return success
|
|
269
267
|
|
|
270
268
|
return 0
|
|
271
269
|
|