Repository navigation
feat: add dakera-haystack integration — self-hosted memory & document store for Haystack - #3515
ferhimedamine wants to merge 9 commits into
Conversation
New integration package: integrations/dakera/ Provides: - DakeraMemoryStore: httpx-based client for Dakera REST API POST /v1/memories (store) + POST /v1/memories/search (recall) - DakeraMemoryRetriever: @component wrapping store.search_memories() - DakeraMemoryWriter: @component wrapping store.store_memories() - Unit tests using respx HTTP mocking (no live server needed) Follows the mem0-haystack package structure exactly. Package name: dakera-haystack (pip install dakera-haystack) Version tag: integrations/dakera-v* Self-host: docker run -p 3000:3000 dakera/dakera:latest
|
Fixing the |
|
I have read the CLA Document and I hereby sign the CLA |
…build CI The CI runs 'hatch run docs:build' which requires: - haystack-pydoc-tools in [tool.hatch.envs.default] dependencies - docs script in [tool.hatch.envs.default.scripts] - pydoc/config_docusaurus.yml pointing to our public module paths Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
Fixed the
Added all three in the latest commit, following the pattern from |
|
I have read the CLA Document and I hereby sign the CLA |
julian-risch
left a comment
There was a problem hiding this comment.
Hi @ferhimedamine thank you for opening this PR and for your patience! There are a couple of smaller issues with the PR that block us from merging it and releasing the integration. Could you please update the PR and address the following issues please?
- test_to_dict_round_trip will fail in CI because the store fixture uses Secret.from_token("test-key"). Should be Secret.from_env_var("DAKERA_API_KEY", strict=False) instead
- The code examples in the README all have errors and can't be run. (import paths, ...)
- Tests are not running because there is no workflow file
I recommend to have a look at integrations/mem0 as an example and potentially use our scaffolding script, which will generate the workflow file automatically for you and also the missing LICENSE.txt: https://github.com/deepset-ai/haystack-core-integrations/blob/main/CONTRIBUTING.md#create-a-new-integration
Addresses @julian-risch review on PR deepset-ai#3515: - tests: use Secret.from_env_var(..., strict=False) so to_dict round-trips. Secret.from_token is not serializable and broke test_to_dict_round_trip. - README: fix the broken import paths, `memory_store=` param and run() args in the usage example; correct the configuration table to the real constructor parameters; add a Contributing section. - add .github/workflows/dakera.yml so tests actually run in CI (modeled on the mem0 integration workflow). - add LICENSE.txt (Apache-2.0). - pyproject: add the hatch `test` env plus ruff/mypy/coverage/pytest config that back the workflow scripts (fmt-check, test:types, test:unit-cov-retry). - wire the integration into labeler.yml, CI_coverage_comment.yml and the root README table. Also fixes two real bugs surfaced while making CI green: - Haystack's structlog logger rejects %-style positional args, so every logger.* call now uses {}-placeholders with keyword args (previously raised TypeError at runtime in the writer/retriever and error paths). - add py.typed markers so `hatch run test:types` (mypy) passes. - guard base_url resolution against a None env value (mypy union-attr). Verified locally: ruff check + ruff format --check clean, mypy clean, 11 unit tests pass at 99% coverage. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks for the thorough review, @julian-risch — all three points are addressed, and I took the 1. 2. README examples
The configuration table now lists the actual constructor parameters, and I added a Contributing section. 3. Tests not running (no workflow) While making CI green I also caught and fixed two real bugs:
CI is now green across the full matrix (Python 3.10 & 3.14 on Linux, Windows, and macOS): https://github.com/deepset-ai/haystack-core-integrations/actions/runs/30078491113 — Ready for another look whenever you have a moment. 🙏 |
julian-risch
left a comment
There was a problem hiding this comment.
@ferhimedamine Thanks for addressing the review. Unfortunately, there are still a number of inconsistencies, for example:
- PR body: docker run -p 3000:3000 vs. README & code default: port 3300
- Untyped output socket. integrations/dakera/src/haystack_integrations/components/retrievers/dakera/retriever.py#L722 uses
@component.output_types(memories=list). mem0's equivalent useslist[ChatMessage]. A bare list weakens pipeline connection type-checking. - integration tests should be added
Thx for feedback @julian-risch , i will adress all reported issues |
…ped ChatMessage sockets Addresses @julian-risch's second review (review-4774305947). A deep audit of the Dakera server source (crates/api) showed the client targeted endpoints and a port that do not exist, so this corrects the integration against the verified API: - Port: default is 3000 (server `DAKERA_PORT`, Dockerfile `EXPOSE 3000`, dakera-deploy), not 3300 — fixed the code default, README and PR body so all three agree. - Routes: create is `POST /v1/memory/store` and recall is `POST /v1/memory/recall` (the previous `/v1/memories` and `/v1/memories/search` do not exist and would 404). - Auth: send `X-API-Key` (the server's default header; it also accepts Bearer). - Schema: identity is `agent_id` (required) — dropped the non-existent `user_id`; recall results are parsed from `memories[]` where each item is `{memory: {...}, score}`. Typed pipeline sockets (review point on the bare `list`): - `DakeraMemoryWriter` now accepts `list[ChatMessage]` and stores each message's text. - `DakeraMemoryRetriever` now declares `@component.output_types(memories=list[ChatMessage])` and returns recalled memories as system-role `ChatMessage` objects, with Dakera fields (id, score, importance, ...) under `meta` — mirroring `integrations/mem0`. Integration tests (review point): added `tests/test_integration.py` (marked `integration`, skipped unless `DAKERA_API_URL` is set) and re-enabled the integration step in the workflow. Verified locally: ruff check + format --check clean, mypy clean, docs build (pydoc) clean, 13 unit tests pass at 93% coverage, integration tests skip without a live server. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks @julian-risch — all three points are addressed, and I did a deeper audit against the Dakera server itself rather than just patching the docs. That surfaced that the client was targeting endpoints/a port that don't actually exist, so I corrected the whole API surface: 1. Port inconsistency (3000 vs 3300) 2. Untyped output socket 3. Integration tests Additional correctness fixes from the audit (these were real bugs):
CI is green across the full matrix (Python 3.10 & 3.14 on Linux, Windows, macOS), including the docs build and the new integration step: https://github.com/deepset-ai/haystack-core-integrations/actions/runs/30109488066 — ruff, mypy, 13 unit tests at 93% coverage. Ready for another look. 🙏 |
…era-haystack package Consolidates the two Dakera-Haystack PRs into a single package (per founder decision): merges the document-store integration (deepset-ai#3519) into the memory integration (deepset-ai#3515), so `dakera-haystack` now ships both, sharing one Dakera server. Brought in from deepset-ai#3519: - document_stores/dakera/{document_store.py, filters.py} — DakeraDocumentStore (sync + async) over the `dakera` SDK vector-namespace API, with metadata filtering. - components/retrievers/dakera/embedding_retriever.py — DakeraEmbeddingRetriever. - tests: test_document_store.py, test_document_store_async.py, test_embedding_retriever.py, test_filters.py, conftest.py, and the mixin-based document integration suite (renamed to test_document_integration.py). The memory integration suite is renamed to test_memory_integration.py. - examples/, CHANGELOG.md, py.typed markers for the document-store packages. Reconciled shared files: - pyproject.toml: dependencies now haystack-ai>=2.28.0 + httpx>=0.27.0 + dakera>=0.12.8; test env gains pytest-xdist; mypy `types` covers all four packages; pytest asyncio auto mode. - components/retrievers/dakera/__init__.py exports both DakeraEmbeddingRetriever and DakeraMemoryRetriever. - README, pydoc config, and CHANGELOG document both the memory and document-store components. - CI matrix pinned to Python 3.10 & 3.13. Verified locally: ruff check + format --check clean, mypy clean over all 4 packages, docs build clean, 74 unit tests pass at 91% coverage, integration tests skip without a live server. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Heads-up on a consolidation, @julian-risch: we had two open PRs for Dakera — this one (#3515, the memory integration) and #3519 (the document-store integration). Since both were building the same
All of your review feedback from both PRs is incorporated:
CI is green across the matrix (Python 3.10 & 3.13 on Linux/Windows/macOS), including the docs build: https://github.com/deepset-ai/haystack-core-integrations/actions/runs/30113924150 — ruff, mypy over all packages, 74 unit tests at 91% coverage; integration tests are skipped in CI (no live server). The updated PR description above reflects the unified package. Ready for another look — thanks for the thorough reviews on both PRs. 🙏 |
…stent headers, version config Proactive review-hardening pass on the consolidated dakera-haystack package: - Async parity: DakeraMemoryStore now has store_memories_async / recall_memories_async, and DakeraMemoryWriter / DakeraMemoryRetriever implement run_async — matching the document store's async support so the whole package is uniformly sync + async. Sync/async share DRY payload builders. Added respx-based async unit tests. - Consistency: unified the SPDX copyright headers across all files to Dakera AI (they were a mix of "deepset GmbH" and "Dakera AI" after the merge). - Versioning: aligned the hatch-vcs config to the repo convention used by mem0/pinecone (`root = "../.."` + `git_describe_command` matching the integration's own tags) instead of the fallback-version style. Verified locally: ruff check + format --check clean, mypy clean over all four packages, docs build clean, a wheel builds with every module + all py.typed markers, the pinned floor `dakera==0.12.8` exports every SDK symbol imported, and 80 unit tests pass at 92% coverage (integration tests skip without a live server). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds end-to-end coverage proving both integrations work inside a Haystack Pipeline: `Pipeline.loads(Pipeline().dumps())` round-trips the components (env-var Secret serialization), and the deserialized pipeline runs — memory (writer + retriever, HTTP mocked with respx) and document store (embedding retriever, SDK mocked). Guards against serialization/wiring regressions a maintainer would exercise. Verified locally: ruff + format clean, 82 unit tests pass (integration tests skip without a live server). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Hi @ferhimedamine and thanks again for opening this PR! I recommend to publish this integration yourselves under https://github.com/Dakera-AI similar to your other framework integration(s). We do have a repository template that you could use for that: https://github.com/deepset-ai/custom-component To support you with the integration, I'd like to share a couple changes that are still required to make this new integration work well in your own repo:
Thanks again for your efforts and good luck with setting up the integration under https://github.com/Dakera-AI! |
|
@julian-risch thx for comment and review, just curious what changed your mind , we were reviewing / working on the internal integration, now the recommendation is external integration |
|
It's a better fit with your other framework integrations. :) |
Closes #3516
Supersedes #3519 (the document-store integration is now included here; #3519 is closed as redundant)
Summary
Adds
integrations/dakera/— a singledakera-haystackpackage for Dakera, a self-hosted memory server. It exposes two complementary integrations that share one Dakera server:DakeraMemoryStore,DakeraMemoryRetriever,DakeraMemoryWriter: conversational, decay-weighted memory over Dakera's memory API (POST /v1/memory/store,POST /v1/memory/recall).ChatMessage-based; the server handles embedding and importance scoring.DakeraDocumentStore,DakeraEmbeddingRetriever: a standard HaystackDocumentStoreover Dakera's vector-namespace API (via the officialdakeraPython SDK), for embedding-based document retrieval (RAG) with metadata filtering.This follows the structure of
integrations/mem0/and (for the document store) theintegrations/pinecone/conventions.Components
DakeraMemoryStoreX-API-KeyauthDakeraMemoryWriter@componentChatMessagetext as memories →memories_written: intDakeraMemoryRetriever@componentmemories: list[ChatMessage]DakeraDocumentStoreDocumentStoredakeraSDKDakeraEmbeddingRetriever@componentTests
respx(memory) andAsyncMock/mocked SDK (document store) — no live server needed in CI.test_memory_integration.py,test_document_integration.py) run against a live Dakera server and are skipped unlessDAKERA_API_URL/DAKERA_URLis set. The document-store suite reuses Haystack'sCountDocumentsTest/DeleteDocumentsTest/WriteDocumentsTestmixins.Notes
dependencies = haystack-ai>=2.28.0, httpx>=0.27.0, dakera>=0.12.8.dakera-deploy; the REST API listens on port3000by default.