neurocore-skill-qdrant 0.1.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.
@@ -0,0 +1,152 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ *.manifest
31
+ *.spec
32
+
33
+ # Installer logs
34
+ pip-log.txt
35
+ pip-delete-this-directory.txt
36
+
37
+ # Unit test / coverage reports
38
+ htmlcov/
39
+ .tox/
40
+ .nox/
41
+ .coverage
42
+ .coverage.*
43
+ .cache
44
+ nosetests.xml
45
+ coverage.xml
46
+ *.cover
47
+ *.py,cover
48
+ .hypothesis/
49
+ .pytest_cache/
50
+ cover/
51
+
52
+ # Translations
53
+ *.mo
54
+ *.pot
55
+
56
+ # Django stuff:
57
+ *.log
58
+ local_settings.py
59
+ db.sqlite3
60
+ db.sqlite3-journal
61
+
62
+ # Flask stuff:
63
+ instance/
64
+ .webassets-cache
65
+
66
+ # Scrapy stuff:
67
+ .scrapy
68
+
69
+ # Sphinx documentation
70
+ docs/_build/
71
+
72
+ # PyBuilder
73
+ .pybuilder/
74
+ target/
75
+
76
+ # Jupyter Notebook
77
+ .ipynb_checkpoints
78
+
79
+ # IPython
80
+ profile_default/
81
+ ipython_config.py
82
+
83
+ # pyenv
84
+ .python-version
85
+
86
+ # pipenv
87
+ Pipfile.lock
88
+
89
+ # poetry
90
+ poetry.lock
91
+
92
+ # pdm
93
+ .pdm.toml
94
+ .pdm-python
95
+ .pdm-build/
96
+
97
+ # PEP 582
98
+ __pypackages__/
99
+
100
+ # Celery stuff
101
+ celerybeat-schedule
102
+ celerybeat.pid
103
+
104
+ # SageMath parsed files
105
+ *.sage.py
106
+
107
+ # Environments
108
+ .env
109
+ .venv
110
+ env/
111
+ venv/
112
+ ENV/
113
+ env.bak/
114
+ venv.bak/
115
+
116
+ # Spyder project settings
117
+ .spyderproject
118
+ .spyproject
119
+
120
+ # Rope project settings
121
+ .ropeproject
122
+
123
+ # mkdocs documentation
124
+ /site
125
+
126
+ # mypy
127
+ .mypy_cache/
128
+ .dmypy.json
129
+ dmypy.json
130
+
131
+ # Pyre type checker
132
+ .pyre/
133
+
134
+ # pytype static type analyzer
135
+ .pytype/
136
+
137
+ # Cython debug symbols
138
+ cython_debug/
139
+
140
+ # Ruff
141
+ .ruff_cache/
142
+
143
+ # IDEs and editors
144
+ .idea/
145
+ .vscode/
146
+ *.swp
147
+ *.swo
148
+ *~
149
+
150
+ # OS files
151
+ .DS_Store
152
+ Thumbs.db
@@ -0,0 +1,47 @@
1
+ Metadata-Version: 2.4
2
+ Name: neurocore-skill-qdrant
3
+ Version: 0.1.0
4
+ Summary: Qdrant vector-search skill for NeuroCore
5
+ Author: NeuroCore Contributors
6
+ License-Expression: Apache-2.0
7
+ Keywords: ai,neurocore,qdrant,rag,skill,vector
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: Apache Software License
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
13
+ Classifier: Typing :: Typed
14
+ Requires-Python: >=3.13
15
+ Requires-Dist: neurocore-ai>=0.2.0
16
+ Requires-Dist: qdrant-client>=1.10
17
+ Provides-Extra: dev
18
+ Requires-Dist: mypy>=1.8; extra == 'dev'
19
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
20
+ Requires-Dist: pytest>=9.0.2; extra == 'dev'
21
+ Requires-Dist: ruff>=0.8; extra == 'dev'
22
+ Description-Content-Type: text/markdown
23
+
24
+ # neurocore-skill-qdrant
25
+
26
+ Vector similarity search for NeuroCore over [Qdrant](https://qdrant.tech).
27
+
28
+ ```bash
29
+ pip install neurocore-skill-qdrant
30
+ docker run -p 6333:6333 qdrant/qdrant
31
+ ```
32
+
33
+ ```yaml
34
+ components:
35
+ - name: retrieve
36
+ type: qdrant
37
+ config:
38
+ collection: documents
39
+ top_k: 5
40
+ flow:
41
+ type: sequential
42
+ steps:
43
+ - component: retrieve
44
+ ```
45
+
46
+ Reads `query_vector` (a list of floats from your embedder); writes
47
+ `qdrant_results` (a list of `{id, score, payload}`).
@@ -0,0 +1,24 @@
1
+ # neurocore-skill-qdrant
2
+
3
+ Vector similarity search for NeuroCore over [Qdrant](https://qdrant.tech).
4
+
5
+ ```bash
6
+ pip install neurocore-skill-qdrant
7
+ docker run -p 6333:6333 qdrant/qdrant
8
+ ```
9
+
10
+ ```yaml
11
+ components:
12
+ - name: retrieve
13
+ type: qdrant
14
+ config:
15
+ collection: documents
16
+ top_k: 5
17
+ flow:
18
+ type: sequential
19
+ steps:
20
+ - component: retrieve
21
+ ```
22
+
23
+ Reads `query_vector` (a list of floats from your embedder); writes
24
+ `qdrant_results` (a list of `{id, score, payload}`).
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "neurocore-skill-qdrant"
7
+ version = "0.1.0"
8
+ description = "Qdrant vector-search skill for NeuroCore"
9
+ readme = "README.md"
10
+ license = "Apache-2.0"
11
+ requires-python = ">=3.13"
12
+ authors = [{ name = "NeuroCore Contributors" }]
13
+ keywords = ["neurocore", "skill", "qdrant", "vector", "rag", "ai"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: Apache Software License",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
20
+ "Typing :: Typed",
21
+ ]
22
+ dependencies = [
23
+ "neurocore-ai>=0.2.0",
24
+ "qdrant-client>=1.10",
25
+ ]
26
+
27
+ [project.optional-dependencies]
28
+ dev = ["pytest>=9.0.2", "pytest-asyncio>=0.24", "ruff>=0.8", "mypy>=1.8"]
29
+
30
+ [project.entry-points."neurocore.skills"]
31
+ qdrant = "neurocore_skill_qdrant:QdrantSkill"
32
+
33
+ [tool.hatch.build.targets.wheel]
34
+ packages = ["src/neurocore_skill_qdrant"]
35
+
36
+ [tool.pytest.ini_options]
37
+ testpaths = ["tests"]
38
+ pythonpath = ["src"]
39
+ asyncio_mode = "auto"
@@ -0,0 +1,5 @@
1
+ """neurocore-skill-qdrant — Qdrant vector-search skill for NeuroCore."""
2
+
3
+ from neurocore_skill_qdrant.skill import QdrantSkill
4
+
5
+ __all__ = ["QdrantSkill"]
@@ -0,0 +1,80 @@
1
+ """QdrantSkill — vector similarity search over a Qdrant collection.
2
+
3
+ Reads a query vector from ``query_vector`` (list[float]) and writes hits to
4
+ ``qdrant_results``.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import asyncio
9
+ import logging
10
+ import os
11
+ from typing import Any
12
+
13
+ from flowengine import FlowContext
14
+
15
+ from neurocore import AsyncSkill, SkillMeta
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class QdrantSkill(AsyncSkill):
21
+ """Async vector search against Qdrant."""
22
+
23
+ skill_meta = SkillMeta(
24
+ name="qdrant",
25
+ version="0.1.0",
26
+ description="Vector similarity search over a Qdrant collection",
27
+ author="NeuroCore Contributors",
28
+ requires=["qdrant-client>=1.10"],
29
+ provides=["qdrant_results"],
30
+ consumes=["query_vector"],
31
+ tags=["vector", "rag", "retrieval"],
32
+ max_retries=2,
33
+ config_schema={
34
+ "required": ["collection"],
35
+ "properties": {
36
+ "url": {"type": "string", "description": "Qdrant URL."},
37
+ "api_key": {"type": "string"},
38
+ "collection": {"type": "string"},
39
+ "top_k": {"type": "integer"},
40
+ },
41
+ },
42
+ )
43
+
44
+ def _build_client(self) -> Any:
45
+ from qdrant_client import QdrantClient # type: ignore[import-untyped]
46
+
47
+ url = self.config.get("url") or os.environ.get(
48
+ "QDRANT_URL", "http://localhost:6333"
49
+ )
50
+ api_key = self.config.get("api_key") or os.environ.get("QDRANT_API_KEY")
51
+ return QdrantClient(url=url, api_key=api_key)
52
+
53
+ async def _search(self, vector: list[float]) -> list[dict[str, Any]]:
54
+ """Run a similarity query and return hit dicts."""
55
+ client = self._build_client()
56
+ collection = self.config["collection"]
57
+ top_k = int(self.config.get("top_k", 5))
58
+
59
+ def _run() -> list[dict[str, Any]]:
60
+ hits = client.query_points(
61
+ collection_name=collection, query=vector, limit=top_k
62
+ ).points
63
+ return [
64
+ {"id": h.id, "score": h.score, "payload": h.payload} for h in hits
65
+ ]
66
+
67
+ return await asyncio.to_thread(_run)
68
+
69
+ async def process(self, context: FlowContext) -> FlowContext:
70
+ vector = context.get("query_vector")
71
+ if not vector:
72
+ logger.warning("QdrantSkill: 'query_vector' is empty.")
73
+ context.set("qdrant_results", [])
74
+ return context
75
+ try:
76
+ context.set("qdrant_results", await self._search(list(vector)))
77
+ except Exception as exc: # noqa: BLE001
78
+ logger.error("QdrantSkill search failed: %s", exc, exc_info=True)
79
+ context.set("qdrant_results", [])
80
+ return context
@@ -0,0 +1,39 @@
1
+ """Tests for QdrantSkill (search mocked via the _search seam)."""
2
+ from __future__ import annotations
3
+
4
+ from flowengine import FlowContext
5
+ from neurocore_skill_qdrant import QdrantSkill
6
+
7
+
8
+ def test_skill_meta():
9
+ meta = QdrantSkill.skill_meta
10
+ assert meta.name == "qdrant"
11
+ assert "qdrant_results" in meta.provides
12
+
13
+
14
+ def test_validate_config_requires_collection():
15
+ skill = QdrantSkill()
16
+ skill.init({})
17
+ assert any("collection" in e for e in skill.validate_config())
18
+
19
+
20
+ async def test_process_sets_results(monkeypatch):
21
+ skill = QdrantSkill()
22
+ skill.init({"collection": "docs"})
23
+
24
+ async def fake_search(vector):
25
+ assert vector == [0.1, 0.2]
26
+ return [{"id": 1, "score": 0.9, "payload": {"text": "hi"}}]
27
+
28
+ monkeypatch.setattr(skill, "_search", fake_search)
29
+ ctx = FlowContext()
30
+ ctx.set("query_vector", [0.1, 0.2])
31
+ out = await skill.process(ctx)
32
+ assert out.get("qdrant_results")[0]["score"] == 0.9
33
+
34
+
35
+ async def test_empty_vector_returns_empty():
36
+ skill = QdrantSkill()
37
+ skill.init({"collection": "docs"})
38
+ out = await skill.process(FlowContext())
39
+ assert out.get("qdrant_results") == []