Skip to content

Commit d41fde2

Browse files
Merge branch 'NevaMind-AI:main' into feat/json-mode-reasoning-effort
2 parents 200c9b7 + bf44de7 commit d41fde2

3 files changed

Lines changed: 110 additions & 11 deletions

File tree

.github/ISSUE_TEMPLATE/feature_request.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,28 @@ body:
1717
validations:
1818
required: true
1919

20+
- type: textarea
21+
id: motivation
22+
attributes:
23+
label: Motivation
24+
description: Why do we need this feature? What problem does it solve?
25+
placeholder: "Explain the use case and why this feature would be valuable."
26+
validations:
27+
required: true
28+
29+
- type: dropdown
30+
id: platform
31+
attributes:
32+
label: Platform
33+
description: Which platform(s) does this feature apply to?
34+
options:
35+
- Platform Independent
36+
- Linux
37+
- macOS
38+
- Windows
39+
validations:
40+
required: true
41+
2042
- type: dropdown
2143
id: priority
2244
attributes:

README.md

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ View detailed experimental data: [memU-experiment](https://github.com/NevaMind-A
356356
<div align="center">
357357

358358
<a href="https://github.com/TEN-framework/ten-framework"><img src="https://avatars.githubusercontent.com/u/113095513?s=200&v=4" alt="Ten" height="40" style="margin: 10px;"></a>
359-
<a href="GitHub - openagents-org/openagents: OpenAgents - AI Agent Networks for Open Collaboration"><img src="assets/partners/openagents.png" alt="OpenAgents" height="40" style="margin: 10px;"></a>
359+
<a href="https://openagents.org"><img src="assets/partners/openagents.png" alt="OpenAgents" height="40" style="margin: 10px;"></a>
360360
<a href="https://github.com/milvus-io/milvus"><img src="https://miro.medium.com/v2/resize:fit:2400/1*-VEGyAgcIBD62XtZWavy8w.png" alt="Milvus" height="40" style="margin: 10px;"></a>
361361
<a href="https://xroute.ai/"><img src="assets/partners/xroute.png" alt="xRoute" height="40" style="margin: 10px;"></a>
362362
<a href="https://jaaz.app/"><img src="assets/partners/jazz.png" alt="Jazz" height="40" style="margin: 10px;"></a>
@@ -368,6 +368,62 @@ View detailed experimental data: [memU-experiment](https://github.com/NevaMind-A
368368

369369
---
370370

371+
## 🤝 How to Contribute
372+
373+
We welcome contributions from the community! Whether you're fixing bugs, adding features, or improving documentation, your help is appreciated.
374+
375+
### Getting Started
376+
377+
To start contributing to MemU, you'll need to set up your development environment:
378+
379+
#### Prerequisites
380+
- Python 3.13+
381+
- [uv](https://github.com/astral-sh/uv) (Python package manager)
382+
- Git
383+
384+
#### Setup Development Environment
385+
386+
```bash
387+
# 1. Fork and clone the repository
388+
git clone https://github.com/YOUR_USERNAME/memU.git
389+
cd memU
390+
391+
# 2. Install development dependencies
392+
make install
393+
```
394+
395+
The `make install` command will:
396+
- Create a virtual environment using `uv`
397+
- Install all project dependencies
398+
- Set up pre-commit hooks for code quality checks
399+
400+
#### Running Quality Checks
401+
402+
Before submitting your contribution, ensure your code passes all quality checks:
403+
404+
```bash
405+
make check
406+
```
407+
408+
The `make check` command runs:
409+
- **Lock file verification**: Ensures `pyproject.toml` consistency
410+
- **Pre-commit hooks**: Lints code with Ruff, formats with Black
411+
- **Type checking**: Runs `mypy` for static type analysis
412+
- **Dependency analysis**: Uses `deptry` to find obsolete dependencies
413+
414+
### Contributing Guidelines
415+
416+
For detailed contribution guidelines, code standards, and development practices, please see [CONTRIBUTING.md](CONTRIBUTING.md).
417+
418+
**Quick tips:**
419+
- Create a new branch for each feature or bug fix
420+
- Write clear commit messages
421+
- Add tests for new functionality
422+
- Update documentation as needed
423+
- Run `make check` before pushing
424+
425+
---
426+
371427
## 📄 License
372428

373429
[Apache License 2.0](LICENSE.txt)
@@ -376,7 +432,7 @@ View detailed experimental data: [memU-experiment](https://github.com/NevaMind-A
376432

377433
## 🌍 Community
378434

379-
- **GitHub Issues**: [Report bugs & request features](NevaMind-AI/memU)
435+
- **GitHub Issues**: [Report bugs & request features](https://github.com/NevaMind-AI/memU/issues)
380436
- **Discord**: [Join the community](https://discord.com/invite/hQZntfGsbJ)
381437
- **X (Twitter)**: [Follow @memU_ai](https://x.com/memU_ai)
382438
- **Contact**: info@nevamind.ai

src/memu/database/inmemory/vector.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,37 @@ def cosine_topk(
1616
corpus: Iterable[tuple[str, list[float] | None]],
1717
k: int = 5,
1818
) -> list[tuple[str, float]]:
19-
q = np.array(query_vec, dtype=np.float32)
20-
scored: list[tuple[str, float]] = []
19+
# Filter out None vectors and collect valid entries
20+
ids: list[str] = []
21+
vecs: list[list[float]] = []
2122
for _id, vec in corpus:
22-
if vec is None:
23-
continue
24-
vec_list = cast(list[float], vec)
25-
v = np.array(vec_list, dtype=np.float32)
26-
scored.append((_id, _cosine(q, v)))
27-
scored.sort(key=lambda x: x[1], reverse=True)
28-
return scored[:k]
23+
if vec is not None:
24+
ids.append(_id)
25+
vecs.append(cast(list[float], vec))
26+
27+
if not vecs:
28+
return []
29+
30+
# Vectorized computation: stack all vectors into a matrix
31+
q = np.array(query_vec, dtype=np.float32)
32+
matrix = np.array(vecs, dtype=np.float32) # shape: (n, dim)
33+
34+
# Compute all cosine similarities at once
35+
q_norm = np.linalg.norm(q)
36+
vec_norms = np.linalg.norm(matrix, axis=1)
37+
scores = matrix @ q / (vec_norms * q_norm + 1e-9)
38+
39+
# Use argpartition for O(n) topk selection instead of O(n log n) sort
40+
n = len(scores)
41+
actual_k = min(k, n)
42+
if actual_k == n:
43+
topk_indices = np.argsort(scores)[::-1]
44+
else:
45+
# Get indices of top k elements (unordered), then sort only those
46+
topk_indices = np.argpartition(scores, -actual_k)[-actual_k:]
47+
topk_indices = topk_indices[np.argsort(scores[topk_indices])[::-1]]
48+
49+
return [(ids[i], float(scores[i])) for i in topk_indices]
2950

3051

3152
def query_cosine(query_vec: list[float], vecs: list[list[float]]) -> list[tuple[int, float]]:

0 commit comments

Comments
 (0)