haiku.rag 0.12.0__tar.gz → 0.13.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 haiku.rag might be problematic. Click here for more details.
- haiku_rag-0.13.0/.dockerignore +66 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/.gitignore +5 -1
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/PKG-INFO +21 -11
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/README.md +17 -7
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/mkdocs.yml +1 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/pyproject.toml +6 -6
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/evaluations/benchmark.py +1 -1
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/evaluations/llm_judge.py +1 -1
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/a2a/__init__.py +3 -3
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/a2a/client.py +52 -55
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/app.py +19 -10
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/chunker.py +1 -1
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/cli.py +74 -33
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/client.py +83 -14
- haiku_rag-0.13.0/src/haiku/rag/config/__init__.py +54 -0
- haiku_rag-0.13.0/src/haiku/rag/config/loader.py +151 -0
- haiku_rag-0.13.0/src/haiku/rag/config/models.py +78 -0
- haiku_rag-0.13.0/src/haiku/rag/embeddings/__init__.py +41 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/embeddings/base.py +10 -2
- haiku_rag-0.12.0/src/haiku/rag/embeddings/vllm.py → haiku_rag-0.13.0/src/haiku/rag/embeddings/ollama.py +9 -1
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/embeddings/openai.py +8 -0
- haiku_rag-0.12.0/src/haiku/rag/embeddings/ollama.py → haiku_rag-0.13.0/src/haiku/rag/embeddings/vllm.py +11 -1
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/embeddings/voyageai.py +8 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/graph/common.py +2 -2
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/mcp.py +14 -8
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/monitor.py +17 -4
- haiku_rag-0.13.0/src/haiku/rag/qa/__init__.py +33 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/qa/agent.py +4 -2
- haiku_rag-0.13.0/src/haiku/rag/reranking/__init__.py +45 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/reranking/base.py +1 -1
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/reranking/cohere.py +2 -2
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/reranking/mxbai.py +1 -1
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/reranking/vllm.py +1 -1
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/store/engine.py +19 -12
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/store/repositories/chunk.py +12 -8
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/store/repositories/document.py +4 -4
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/store/repositories/settings.py +19 -9
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/utils.py +9 -9
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/uv.lock +67 -65
- haiku_rag-0.12.0/src/haiku/rag/config.py +0 -90
- haiku_rag-0.12.0/src/haiku/rag/embeddings/__init__.py +0 -35
- haiku_rag-0.12.0/src/haiku/rag/migration.py +0 -316
- haiku_rag-0.12.0/src/haiku/rag/qa/__init__.py +0 -20
- haiku_rag-0.12.0/src/haiku/rag/reranking/__init__.py +0 -37
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/.pre-commit-config.yaml +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/.python-version +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/LICENSE +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/server.json +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/evaluations/__init__.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/evaluations/config.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/evaluations/datasets/__init__.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/evaluations/datasets/repliqa.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/evaluations/datasets/wix.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/evaluations/prompts.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/__init__.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/a2a/context.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/a2a/models.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/a2a/prompts.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/a2a/skills.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/a2a/storage.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/a2a/worker.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/graph/__init__.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/graph/base.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/graph/models.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/graph/nodes/__init__.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/graph/nodes/analysis.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/graph/nodes/plan.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/graph/nodes/search.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/graph/nodes/synthesize.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/graph/prompts.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/logging.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/qa/deep/__init__.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/qa/deep/dependencies.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/qa/deep/graph.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/qa/deep/models.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/qa/deep/nodes.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/qa/deep/prompts.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/qa/deep/state.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/qa/prompts.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/reader.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/research/__init__.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/research/common.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/research/dependencies.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/research/graph.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/research/models.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/research/prompts.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/research/state.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/research/stream.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/store/__init__.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/store/models/__init__.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/store/models/chunk.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/store/models/document.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/store/repositories/__init__.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/store/upgrades/__init__.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/store/upgrades/v0_10_1.py +0 -0
- {haiku_rag-0.12.0 → haiku_rag-0.13.0}/src/haiku/rag/store/upgrades/v0_9_3.py +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments (uv best practice)
|
|
24
|
+
.venv/
|
|
25
|
+
venv/
|
|
26
|
+
env/
|
|
27
|
+
|
|
28
|
+
# Node.js
|
|
29
|
+
node_modules/
|
|
30
|
+
.next/
|
|
31
|
+
npm-debug.log*
|
|
32
|
+
yarn-debug.log*
|
|
33
|
+
yarn-error.log*
|
|
34
|
+
|
|
35
|
+
# Data
|
|
36
|
+
*.lancedb/
|
|
37
|
+
data/
|
|
38
|
+
|
|
39
|
+
# Docs
|
|
40
|
+
mkdocs.yml
|
|
41
|
+
docs/
|
|
42
|
+
|
|
43
|
+
# IDE
|
|
44
|
+
.vscode/
|
|
45
|
+
.idea/
|
|
46
|
+
*.swp
|
|
47
|
+
*.swo
|
|
48
|
+
*~
|
|
49
|
+
|
|
50
|
+
# OS
|
|
51
|
+
.DS_Store
|
|
52
|
+
Thumbs.db
|
|
53
|
+
|
|
54
|
+
# Git
|
|
55
|
+
.git/
|
|
56
|
+
.gitignore
|
|
57
|
+
|
|
58
|
+
# Development
|
|
59
|
+
tests/
|
|
60
|
+
.pytest_cache/
|
|
61
|
+
.coverage
|
|
62
|
+
htmlcov/
|
|
63
|
+
src/evaluations/
|
|
64
|
+
server.json
|
|
65
|
+
# Examples
|
|
66
|
+
examples/
|
|
@@ -16,8 +16,9 @@ tests/data/
|
|
|
16
16
|
.pytest_cache/
|
|
17
17
|
.ruff_cache/
|
|
18
18
|
|
|
19
|
-
# environment variables
|
|
19
|
+
# environment variables and config files
|
|
20
20
|
.env
|
|
21
|
+
haiku.rag.yaml
|
|
21
22
|
TODO.md
|
|
22
23
|
PLAN.md
|
|
23
24
|
DEVNOTES.md
|
|
@@ -25,3 +26,6 @@ DEVNOTES.md
|
|
|
25
26
|
# mcp registry
|
|
26
27
|
.mcpregistry_github_token
|
|
27
28
|
.mcpregistry_registry_token
|
|
29
|
+
|
|
30
|
+
# MkDocs site directory when doing local docs builds
|
|
31
|
+
site/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haiku.rag
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.0
|
|
4
4
|
Summary: Agentic Retrieval Augmented Generation (RAG) with LanceDB
|
|
5
5
|
Author-email: Yiorgis Gozadinos <ggozadinos@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -13,9 +13,8 @@ Classifier: Operating System :: MacOS
|
|
|
13
13
|
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
|
14
14
|
Classifier: Operating System :: Microsoft :: Windows :: Windows 11
|
|
15
15
|
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Classifier: Typing :: Typed
|
|
20
19
|
Requires-Python: >=3.12
|
|
21
20
|
Requires-Dist: docling>=2.56.1
|
|
@@ -24,8 +23,9 @@ Requires-Dist: httpx>=0.28.1
|
|
|
24
23
|
Requires-Dist: lancedb>=0.25.2
|
|
25
24
|
Requires-Dist: pydantic-ai>=1.0.18
|
|
26
25
|
Requires-Dist: pydantic-graph>=1.0.18
|
|
27
|
-
Requires-Dist: pydantic>=2.12.
|
|
26
|
+
Requires-Dist: pydantic>=2.12.2
|
|
28
27
|
Requires-Dist: python-dotenv>=1.1.1
|
|
28
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
29
29
|
Requires-Dist: rich>=14.2.0
|
|
30
30
|
Requires-Dist: tiktoken>=0.12.0
|
|
31
31
|
Requires-Dist: typer>=0.19.2
|
|
@@ -44,7 +44,7 @@ Retrieval-Augmented Generation (RAG) library built on LanceDB.
|
|
|
44
44
|
|
|
45
45
|
`haiku.rag` is a Retrieval-Augmented Generation (RAG) library built to work with LanceDB as a local vector database. It uses LanceDB for storing embeddings and performs semantic (vector) search as well as full-text search combined through native hybrid search with Reciprocal Rank Fusion. Both open-source (Ollama) as well as commercial (OpenAI, VoyageAI) embedding providers are supported.
|
|
46
46
|
|
|
47
|
-
> **Note**:
|
|
47
|
+
> **Note**: Configuration now uses YAML files instead of environment variables. If you're upgrading from an older version, run `haiku-rag init-config --from-env` to migrate your `.env` file to `haiku.rag.yaml`. See [Configuration](https://ggozad.github.io/haiku.rag/configuration/) for details.
|
|
48
48
|
|
|
49
49
|
## Features
|
|
50
50
|
|
|
@@ -65,6 +65,7 @@ Retrieval-Augmented Generation (RAG) library built on LanceDB.
|
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
67
|
# Install
|
|
68
|
+
# Python 3.12 or newer required
|
|
68
69
|
uv pip install haiku.rag
|
|
69
70
|
|
|
70
71
|
# Add documents
|
|
@@ -98,14 +99,12 @@ haiku-rag research \
|
|
|
98
99
|
# Rebuild database (re-chunk and re-embed all documents)
|
|
99
100
|
haiku-rag rebuild
|
|
100
101
|
|
|
101
|
-
# Migrate from SQLite to LanceDB
|
|
102
|
-
haiku-rag migrate old_database.sqlite
|
|
103
|
-
|
|
104
102
|
# Start server with file monitoring
|
|
105
|
-
|
|
106
|
-
haiku-rag serve
|
|
103
|
+
haiku-rag serve --monitor
|
|
107
104
|
```
|
|
108
105
|
|
|
106
|
+
To customize settings, create a `haiku.rag.yaml` config file (see [Configuration](https://ggozad.github.io/haiku.rag/configuration/)).
|
|
107
|
+
|
|
109
108
|
## Python Usage
|
|
110
109
|
|
|
111
110
|
```python
|
|
@@ -197,18 +196,29 @@ haiku-rag a2aclient
|
|
|
197
196
|
```
|
|
198
197
|
|
|
199
198
|
The A2A agent provides:
|
|
199
|
+
|
|
200
200
|
- Multi-turn dialogue with context
|
|
201
201
|
- Intelligent multi-search for complex questions
|
|
202
202
|
- Source citations with titles and URIs
|
|
203
203
|
- Full document retrieval on request
|
|
204
204
|
|
|
205
|
+
## Examples
|
|
206
|
+
|
|
207
|
+
See the [examples directory](examples/) for working examples:
|
|
208
|
+
|
|
209
|
+
- **[Interactive Research Assistant](examples/ag-ui-research/)** - Full-stack research assistant with Pydantic AI and AG-UI featuring human-in-the-loop approval and real-time state synchronization
|
|
210
|
+
- **[Docker Setup](examples/docker/)** - Complete Docker deployment with file monitoring, MCP server, and A2A agent
|
|
211
|
+
- **[A2A Security](examples/a2a-security/)** - Authentication examples (API key, OAuth2, GitHub)
|
|
212
|
+
|
|
205
213
|
## Documentation
|
|
206
214
|
|
|
207
215
|
Full documentation at: https://ggozad.github.io/haiku.rag/
|
|
208
216
|
|
|
209
217
|
- [Installation](https://ggozad.github.io/haiku.rag/installation/) - Provider setup
|
|
210
|
-
- [Configuration](https://ggozad.github.io/haiku.rag/configuration/) -
|
|
218
|
+
- [Configuration](https://ggozad.github.io/haiku.rag/configuration/) - YAML configuration
|
|
211
219
|
- [CLI](https://ggozad.github.io/haiku.rag/cli/) - Command reference
|
|
212
220
|
- [Python API](https://ggozad.github.io/haiku.rag/python/) - Complete API docs
|
|
213
221
|
- [Agents](https://ggozad.github.io/haiku.rag/agents/) - QA agent and multi-agent research
|
|
222
|
+
- [MCP Server](https://ggozad.github.io/haiku.rag/mcp/) - Model Context Protocol integration
|
|
223
|
+
- [A2A Agent](https://ggozad.github.io/haiku.rag/a2a/) - Agent-to-Agent protocol support
|
|
214
224
|
- [Benchmarks](https://ggozad.github.io/haiku.rag/benchmarks/) - Performance Benchmarks
|
|
@@ -4,7 +4,7 @@ Retrieval-Augmented Generation (RAG) library built on LanceDB.
|
|
|
4
4
|
|
|
5
5
|
`haiku.rag` is a Retrieval-Augmented Generation (RAG) library built to work with LanceDB as a local vector database. It uses LanceDB for storing embeddings and performs semantic (vector) search as well as full-text search combined through native hybrid search with Reciprocal Rank Fusion. Both open-source (Ollama) as well as commercial (OpenAI, VoyageAI) embedding providers are supported.
|
|
6
6
|
|
|
7
|
-
> **Note**:
|
|
7
|
+
> **Note**: Configuration now uses YAML files instead of environment variables. If you're upgrading from an older version, run `haiku-rag init-config --from-env` to migrate your `.env` file to `haiku.rag.yaml`. See [Configuration](https://ggozad.github.io/haiku.rag/configuration/) for details.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
@@ -25,6 +25,7 @@ Retrieval-Augmented Generation (RAG) library built on LanceDB.
|
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
# Install
|
|
28
|
+
# Python 3.12 or newer required
|
|
28
29
|
uv pip install haiku.rag
|
|
29
30
|
|
|
30
31
|
# Add documents
|
|
@@ -58,14 +59,12 @@ haiku-rag research \
|
|
|
58
59
|
# Rebuild database (re-chunk and re-embed all documents)
|
|
59
60
|
haiku-rag rebuild
|
|
60
61
|
|
|
61
|
-
# Migrate from SQLite to LanceDB
|
|
62
|
-
haiku-rag migrate old_database.sqlite
|
|
63
|
-
|
|
64
62
|
# Start server with file monitoring
|
|
65
|
-
|
|
66
|
-
haiku-rag serve
|
|
63
|
+
haiku-rag serve --monitor
|
|
67
64
|
```
|
|
68
65
|
|
|
66
|
+
To customize settings, create a `haiku.rag.yaml` config file (see [Configuration](https://ggozad.github.io/haiku.rag/configuration/)).
|
|
67
|
+
|
|
69
68
|
## Python Usage
|
|
70
69
|
|
|
71
70
|
```python
|
|
@@ -157,18 +156,29 @@ haiku-rag a2aclient
|
|
|
157
156
|
```
|
|
158
157
|
|
|
159
158
|
The A2A agent provides:
|
|
159
|
+
|
|
160
160
|
- Multi-turn dialogue with context
|
|
161
161
|
- Intelligent multi-search for complex questions
|
|
162
162
|
- Source citations with titles and URIs
|
|
163
163
|
- Full document retrieval on request
|
|
164
164
|
|
|
165
|
+
## Examples
|
|
166
|
+
|
|
167
|
+
See the [examples directory](examples/) for working examples:
|
|
168
|
+
|
|
169
|
+
- **[Interactive Research Assistant](examples/ag-ui-research/)** - Full-stack research assistant with Pydantic AI and AG-UI featuring human-in-the-loop approval and real-time state synchronization
|
|
170
|
+
- **[Docker Setup](examples/docker/)** - Complete Docker deployment with file monitoring, MCP server, and A2A agent
|
|
171
|
+
- **[A2A Security](examples/a2a-security/)** - Authentication examples (API key, OAuth2, GitHub)
|
|
172
|
+
|
|
165
173
|
## Documentation
|
|
166
174
|
|
|
167
175
|
Full documentation at: https://ggozad.github.io/haiku.rag/
|
|
168
176
|
|
|
169
177
|
- [Installation](https://ggozad.github.io/haiku.rag/installation/) - Provider setup
|
|
170
|
-
- [Configuration](https://ggozad.github.io/haiku.rag/configuration/) -
|
|
178
|
+
- [Configuration](https://ggozad.github.io/haiku.rag/configuration/) - YAML configuration
|
|
171
179
|
- [CLI](https://ggozad.github.io/haiku.rag/cli/) - Command reference
|
|
172
180
|
- [Python API](https://ggozad.github.io/haiku.rag/python/) - Complete API docs
|
|
173
181
|
- [Agents](https://ggozad.github.io/haiku.rag/agents/) - QA agent and multi-agent research
|
|
182
|
+
- [MCP Server](https://ggozad.github.io/haiku.rag/mcp/) - Model Context Protocol integration
|
|
183
|
+
- [A2A Agent](https://ggozad.github.io/haiku.rag/a2a/) - Agent-to-Agent protocol support
|
|
174
184
|
- [Benchmarks](https://ggozad.github.io/haiku.rag/benchmarks/) - Performance Benchmarks
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
name = "haiku.rag"
|
|
4
4
|
description = "Agentic Retrieval Augmented Generation (RAG) with LanceDB"
|
|
5
|
-
version = "0.
|
|
5
|
+
version = "0.13.0"
|
|
6
6
|
authors = [{ name = "Yiorgis Gozadinos", email = "ggozadinos@gmail.com" }]
|
|
7
7
|
license = { text = "MIT" }
|
|
8
8
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
@@ -16,9 +16,8 @@ classifiers = [
|
|
|
16
16
|
"Operating System :: Microsoft :: Windows :: Windows 11",
|
|
17
17
|
"Operating System :: MacOS",
|
|
18
18
|
"Operating System :: POSIX :: Linux",
|
|
19
|
-
"Programming Language :: Python :: 3.10",
|
|
20
|
-
"Programming Language :: Python :: 3.11",
|
|
21
19
|
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
22
21
|
"Typing :: Typed",
|
|
23
22
|
]
|
|
24
23
|
|
|
@@ -27,10 +26,11 @@ dependencies = [
|
|
|
27
26
|
"fastmcp>=2.12.4",
|
|
28
27
|
"httpx>=0.28.1",
|
|
29
28
|
"lancedb>=0.25.2",
|
|
30
|
-
"pydantic>=2.12.
|
|
29
|
+
"pydantic>=2.12.2",
|
|
31
30
|
"pydantic-ai>=1.0.18",
|
|
32
31
|
"pydantic-graph>=1.0.18",
|
|
33
32
|
"python-dotenv>=1.1.1",
|
|
33
|
+
"pyyaml>=6.0.1",
|
|
34
34
|
"rich>=14.2.0",
|
|
35
35
|
"tiktoken>=0.12.0",
|
|
36
36
|
"typer>=0.19.2",
|
|
@@ -50,7 +50,7 @@ requires = ["hatchling"]
|
|
|
50
50
|
build-backend = "hatchling.build"
|
|
51
51
|
|
|
52
52
|
[tool.hatch.build]
|
|
53
|
-
exclude = ["/docs", "/examples", "/tests", "/.github"]
|
|
53
|
+
exclude = ["/docs", "/examples", "/tests", "/docker", "/.github"]
|
|
54
54
|
|
|
55
55
|
[tool.hatch.build.targets.wheel]
|
|
56
56
|
packages = ["src/haiku"]
|
|
@@ -63,7 +63,7 @@ dev = [
|
|
|
63
63
|
"mkdocs-material>=9.6.14",
|
|
64
64
|
"pydantic-evals>=1.0.8",
|
|
65
65
|
"pre-commit>=4.2.0",
|
|
66
|
-
"pyright>=1.1.
|
|
66
|
+
"pyright>=1.1.406",
|
|
67
67
|
"pytest>=8.4.2",
|
|
68
68
|
"pytest-asyncio>=1.2.0",
|
|
69
69
|
"pytest-cov>=7.0.0",
|
|
@@ -174,7 +174,7 @@ async def run_qa_benchmark(
|
|
|
174
174
|
|
|
175
175
|
judge_model = OpenAIChatModel(
|
|
176
176
|
model_name=QA_JUDGE_MODEL,
|
|
177
|
-
provider=OllamaProvider(base_url=f"{Config.
|
|
177
|
+
provider=OllamaProvider(base_url=f"{Config.providers.ollama.base_url}/v1"),
|
|
178
178
|
)
|
|
179
179
|
|
|
180
180
|
evaluation_dataset = EvalDataset[str, str, dict[str, str]](
|
|
@@ -41,7 +41,7 @@ class LLMJudge:
|
|
|
41
41
|
# Create Ollama model
|
|
42
42
|
ollama_model = OpenAIChatModel(
|
|
43
43
|
model_name=model,
|
|
44
|
-
provider=OllamaProvider(base_url=f"{Config.
|
|
44
|
+
provider=OllamaProvider(base_url=f"{Config.providers.ollama.base_url}/v1"),
|
|
45
45
|
)
|
|
46
46
|
|
|
47
47
|
# Create Pydantic AI agent
|
|
@@ -57,12 +57,12 @@ def create_a2a_app(
|
|
|
57
57
|
"""
|
|
58
58
|
base_storage = InMemoryStorage()
|
|
59
59
|
storage = LRUMemoryStorage(
|
|
60
|
-
storage=base_storage, max_contexts=Config.
|
|
60
|
+
storage=base_storage, max_contexts=Config.a2a.max_contexts
|
|
61
61
|
)
|
|
62
62
|
broker = InMemoryBroker()
|
|
63
63
|
|
|
64
64
|
# Create the agent with native search tool
|
|
65
|
-
model = get_model(Config.
|
|
65
|
+
model = get_model(Config.qa.provider, Config.qa.model)
|
|
66
66
|
agent = Agent(
|
|
67
67
|
model=model,
|
|
68
68
|
deps_type=AgentDependencies,
|
|
@@ -120,7 +120,7 @@ def create_a2a_app(
|
|
|
120
120
|
# Create FastA2A app with custom worker lifecycle
|
|
121
121
|
@asynccontextmanager
|
|
122
122
|
async def lifespan(app):
|
|
123
|
-
logger.info(f"Started A2A server (max contexts: {Config.
|
|
123
|
+
logger.info(f"Started A2A server (max contexts: {Config.a2a.max_contexts})")
|
|
124
124
|
async with app.task_manager:
|
|
125
125
|
async with worker.run():
|
|
126
126
|
yield
|
|
@@ -7,9 +7,18 @@ from rich.console import Console
|
|
|
7
7
|
from rich.markdown import Markdown
|
|
8
8
|
from rich.prompt import Prompt
|
|
9
9
|
|
|
10
|
+
try:
|
|
11
|
+
from fasta2a.client import A2AClient as FastA2AClient
|
|
12
|
+
from fasta2a.schema import Message, TextPart
|
|
13
|
+
except ImportError as e:
|
|
14
|
+
raise ImportError(
|
|
15
|
+
"A2A support requires the 'a2a' extra. "
|
|
16
|
+
"Install with: uv pip install 'haiku.rag[a2a]'"
|
|
17
|
+
) from e
|
|
18
|
+
|
|
10
19
|
|
|
11
20
|
class A2AClient:
|
|
12
|
-
"""
|
|
21
|
+
"""Interactive A2A protocol client."""
|
|
13
22
|
|
|
14
23
|
def __init__(self, base_url: str = "http://localhost:8000"):
|
|
15
24
|
"""Initialize A2A client.
|
|
@@ -18,11 +27,12 @@ class A2AClient:
|
|
|
18
27
|
base_url: Base URL of the A2A server
|
|
19
28
|
"""
|
|
20
29
|
self.base_url = base_url.rstrip("/")
|
|
21
|
-
|
|
30
|
+
http_client = httpx.AsyncClient(timeout=60.0)
|
|
31
|
+
self._client = FastA2AClient(base_url=base_url, http_client=http_client)
|
|
22
32
|
|
|
23
33
|
async def close(self):
|
|
24
34
|
"""Close the HTTP client."""
|
|
25
|
-
await self.
|
|
35
|
+
await self._client.http_client.aclose()
|
|
26
36
|
|
|
27
37
|
async def get_agent_card(self) -> dict[str, Any]:
|
|
28
38
|
"""Fetch the agent card from the A2A server.
|
|
@@ -30,7 +40,9 @@ class A2AClient:
|
|
|
30
40
|
Returns:
|
|
31
41
|
Agent card dictionary with agent capabilities and metadata
|
|
32
42
|
"""
|
|
33
|
-
response = await self.
|
|
43
|
+
response = await self._client.http_client.get(
|
|
44
|
+
f"{self.base_url}/.well-known/agent-card.json"
|
|
45
|
+
)
|
|
34
46
|
response.raise_for_status()
|
|
35
47
|
return response.json()
|
|
36
48
|
|
|
@@ -53,46 +65,38 @@ class A2AClient:
|
|
|
53
65
|
if context_id is None:
|
|
54
66
|
context_id = str(uuid.uuid4())
|
|
55
67
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
"contextId": context_id,
|
|
63
|
-
"message": {
|
|
64
|
-
"kind": "message",
|
|
65
|
-
"role": "user",
|
|
66
|
-
"messageId": message_id,
|
|
67
|
-
"parts": [{"kind": "text", "text": text}],
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
"id": 1,
|
|
71
|
-
}
|
|
68
|
+
message = Message(
|
|
69
|
+
kind="message",
|
|
70
|
+
role="user",
|
|
71
|
+
message_id=str(uuid.uuid4()),
|
|
72
|
+
parts=[TextPart(kind="text", text=text)],
|
|
73
|
+
)
|
|
72
74
|
|
|
75
|
+
metadata: dict[str, Any] = {"contextId": context_id}
|
|
73
76
|
if skill_id:
|
|
74
|
-
|
|
77
|
+
metadata["skillId"] = skill_id
|
|
75
78
|
|
|
76
|
-
response = await self.
|
|
77
|
-
self.base_url,
|
|
78
|
-
json=payload,
|
|
79
|
-
headers={"Content-Type": "application/json"},
|
|
80
|
-
)
|
|
81
|
-
response.raise_for_status()
|
|
82
|
-
initial_response = response.json()
|
|
79
|
+
response = await self._client.send_message(message, metadata=metadata)
|
|
83
80
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
task_id = result.get("id")
|
|
81
|
+
if "error" in response:
|
|
82
|
+
return {"error": response["error"]}
|
|
87
83
|
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
result = response.get("result")
|
|
85
|
+
if not result:
|
|
86
|
+
return {"result": result}
|
|
90
87
|
|
|
91
|
-
#
|
|
92
|
-
|
|
88
|
+
# Result can be either Task or Message - check if it's a Task with an id
|
|
89
|
+
if result.get("kind") == "task":
|
|
90
|
+
task_id = result.get("id")
|
|
91
|
+
if task_id:
|
|
92
|
+
# Poll for task completion
|
|
93
|
+
return await self.wait_for_task(task_id)
|
|
94
|
+
|
|
95
|
+
# Return the message directly
|
|
96
|
+
return {"result": result}
|
|
93
97
|
|
|
94
98
|
async def wait_for_task(
|
|
95
|
-
self, task_id: str, max_wait: int =
|
|
99
|
+
self, task_id: str, max_wait: int = 120, poll_interval: float = 0.5
|
|
96
100
|
) -> dict[str, Any]:
|
|
97
101
|
"""Poll for task completion.
|
|
98
102
|
|
|
@@ -109,27 +113,19 @@ class A2AClient:
|
|
|
109
113
|
start_time = time.time()
|
|
110
114
|
|
|
111
115
|
while time.time() - start_time < max_wait:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
"
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
headers={"Content-Type": "application/json"},
|
|
123
|
-
)
|
|
124
|
-
response.raise_for_status()
|
|
125
|
-
task = response.json()
|
|
126
|
-
|
|
127
|
-
result = task.get("result", {})
|
|
128
|
-
status = result.get("status", {})
|
|
129
|
-
state = status.get("state")
|
|
116
|
+
task_response = await self._client.get_task(task_id)
|
|
117
|
+
|
|
118
|
+
if "error" in task_response:
|
|
119
|
+
return {"error": task_response["error"]}
|
|
120
|
+
|
|
121
|
+
task = task_response.get("result")
|
|
122
|
+
if not task:
|
|
123
|
+
raise Exception("No task in response")
|
|
124
|
+
|
|
125
|
+
state = task.get("status", {}).get("state")
|
|
130
126
|
|
|
131
127
|
if state == "completed":
|
|
132
|
-
return task
|
|
128
|
+
return {"result": task}
|
|
133
129
|
elif state == "failed":
|
|
134
130
|
raise Exception(f"Task failed: {task}")
|
|
135
131
|
|
|
@@ -191,6 +187,7 @@ def print_response(response: dict[str, Any], console: Console):
|
|
|
191
187
|
|
|
192
188
|
# Print artifacts summary with details
|
|
193
189
|
if artifacts:
|
|
190
|
+
console.rule("[dim]Artifacts generated[/dim]")
|
|
194
191
|
summary_lines = []
|
|
195
192
|
|
|
196
193
|
for artifact in artifacts:
|
|
@@ -160,13 +160,20 @@ class HaikuRAGApp:
|
|
|
160
160
|
self, source: str, title: str | None = None, metadata: dict | None = None
|
|
161
161
|
):
|
|
162
162
|
async with HaikuRAG(db_path=self.db_path) as self.client:
|
|
163
|
-
|
|
163
|
+
result = await self.client.create_document_from_source(
|
|
164
164
|
source, title=title, metadata=metadata
|
|
165
165
|
)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
166
|
+
if isinstance(result, list):
|
|
167
|
+
for doc in result:
|
|
168
|
+
self._rich_print_document(doc, truncate=True)
|
|
169
|
+
self.console.print(
|
|
170
|
+
f"[bold green]{len(result)} documents added successfully.[/bold green]"
|
|
171
|
+
)
|
|
172
|
+
else:
|
|
173
|
+
self._rich_print_document(result, truncate=True)
|
|
174
|
+
self.console.print(
|
|
175
|
+
f"[bold green]Document {result.id} added successfully.[/bold green]"
|
|
176
|
+
)
|
|
170
177
|
|
|
171
178
|
async def get_document(self, doc_id: str):
|
|
172
179
|
async with HaikuRAG(db_path=self.db_path) as self.client:
|
|
@@ -224,8 +231,8 @@ class HaikuRAGApp:
|
|
|
224
231
|
)
|
|
225
232
|
|
|
226
233
|
start_node = DeepQAPlanNode(
|
|
227
|
-
provider=Config.
|
|
228
|
-
model=Config.
|
|
234
|
+
provider=Config.qa.provider,
|
|
235
|
+
model=Config.qa.model,
|
|
229
236
|
)
|
|
230
237
|
|
|
231
238
|
result = await graph.run(
|
|
@@ -271,8 +278,8 @@ class HaikuRAGApp:
|
|
|
271
278
|
)
|
|
272
279
|
|
|
273
280
|
start = PlanNode(
|
|
274
|
-
provider=Config.
|
|
275
|
-
model=Config.
|
|
281
|
+
provider=Config.research.provider or Config.qa.provider,
|
|
282
|
+
model=Config.research.model or Config.qa.model,
|
|
276
283
|
)
|
|
277
284
|
report = None
|
|
278
285
|
async for event in stream_research_graph(graph, start, state, deps):
|
|
@@ -467,7 +474,9 @@ class HaikuRAGApp:
|
|
|
467
474
|
|
|
468
475
|
# Start file monitor if enabled
|
|
469
476
|
if enable_monitor:
|
|
470
|
-
monitor = FileWatcher(
|
|
477
|
+
monitor = FileWatcher(
|
|
478
|
+
paths=Config.storage.monitor_directories, client=client
|
|
479
|
+
)
|
|
471
480
|
monitor_task = asyncio.create_task(monitor.observe())
|
|
472
481
|
tasks.append(monitor_task)
|
|
473
482
|
|