pydantic-rag-agent 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.
Files changed (51) hide show
  1. pydantic_rag_agent-0.1.0/LICENSE +21 -0
  2. pydantic_rag_agent-0.1.0/PKG-INFO +247 -0
  3. pydantic_rag_agent-0.1.0/README.md +195 -0
  4. pydantic_rag_agent-0.1.0/pyproject.toml +138 -0
  5. pydantic_rag_agent-0.1.0/pyproject.toml.orig +144 -0
  6. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/__init__.py +99 -0
  7. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/__init__.py +1 -0
  8. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/agent.py +400 -0
  9. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/captioning.py +93 -0
  10. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/chroma_store.py +277 -0
  11. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/compaction.py +107 -0
  12. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/conversations.py +115 -0
  13. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/document_store/__init__.py +1 -0
  14. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/document_store/_keys.py +43 -0
  15. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/document_store/local.py +76 -0
  16. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/document_store/s3.py +109 -0
  17. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/image_store.py +68 -0
  18. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/loaders/__init__.py +18 -0
  19. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/loaders/_tables.py +27 -0
  20. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/loaders/docx.py +209 -0
  21. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/loaders/pdf.py +132 -0
  22. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/loaders/pptx.py +150 -0
  23. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/loaders/text.py +94 -0
  24. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/adapters/memory_store.py +149 -0
  25. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/agent.py +648 -0
  26. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/application/__init__.py +4 -0
  27. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/application/chunking.py +180 -0
  28. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/application/citations.py +59 -0
  29. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/application/embedding.py +78 -0
  30. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/application/evaluation.py +182 -0
  31. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/application/index_guard.py +41 -0
  32. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/application/ingestion.py +421 -0
  33. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/application/retrieval.py +88 -0
  34. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/cli.py +699 -0
  35. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/client.py +200 -0
  36. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/config.py +342 -0
  37. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/domain/__init__.py +1 -0
  38. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/domain/errors.py +37 -0
  39. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/domain/extraction.py +58 -0
  40. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/domain/models.py +240 -0
  41. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/domain/ports.py +130 -0
  42. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/extras.py +43 -0
  43. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/in_process.py +270 -0
  44. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/integrations/__init__.py +1 -0
  45. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/integrations/fastapi/__init__.py +14 -0
  46. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/integrations/fastapi/app.py +333 -0
  47. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/integrations/fastapi/openai.py +338 -0
  48. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/integrations/fastapi/schemas.py +97 -0
  49. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/py.typed +0 -0
  50. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/ui/__init__.py +1 -0
  51. pydantic_rag_agent-0.1.0/src/pydantic_rag_agent/ui/streamlit_app.py +259 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nick
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,247 @@
1
+ Metadata-Version: 2.4
2
+ Name: pydantic-rag-agent
3
+ Version: 0.1.0
4
+ Summary: A RAG agent built on Pydantic.
5
+ Keywords: rag,retrieval-augmented-generation,pydantic,pydantic-ai,llm,vector-search
6
+ Author: Nick
7
+ Author-email: Nick <98120512+hanku4u@users.noreply.github.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Framework :: FastAPI
13
+ Classifier: Framework :: Pydantic
14
+ Classifier: Framework :: Pydantic :: 2
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Typing :: Typed
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: Text Processing :: Indexing
22
+ Requires-Dist: httpx>=0.28.1
23
+ Requires-Dist: pillow>=13.0.0
24
+ Requires-Dist: pydantic>=2.14.1
25
+ Requires-Dist: pydantic-ai-slim[openai]>=2.61,<3
26
+ Requires-Dist: pydantic-settings>=2.16.1
27
+ Requires-Dist: pypdfium2>=5.14.0
28
+ Requires-Dist: python-docx>=1.2.0
29
+ Requires-Dist: python-dotenv>=1.2.4
30
+ Requires-Dist: python-pptx>=1.0.2
31
+ Requires-Dist: rich>=15.0.0
32
+ Requires-Dist: tiktoken>=0.14.0
33
+ Requires-Dist: typer>=0.27.3
34
+ Requires-Dist: pydantic-rag-agent[chroma,api,ui,s3] ; extra == 'all'
35
+ Requires-Dist: fastapi>=0.162.0 ; extra == 'api'
36
+ Requires-Dist: python-multipart>=0.0.32 ; extra == 'api'
37
+ Requires-Dist: uvicorn[standard]>=0.54.0 ; extra == 'api'
38
+ Requires-Dist: chromadb>=1.5.9 ; extra == 'chroma'
39
+ Requires-Dist: boto3>=1.35 ; extra == 's3'
40
+ Requires-Dist: streamlit>=1.66.1 ; extra == 'ui'
41
+ Requires-Python: >=3.11
42
+ Project-URL: Homepage, https://github.com/hanku4u/pydantic-rag-agent
43
+ Project-URL: Repository, https://github.com/hanku4u/pydantic-rag-agent
44
+ Project-URL: Documentation, https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/README.md
45
+ Project-URL: Issues, https://github.com/hanku4u/pydantic-rag-agent/issues
46
+ Provides-Extra: all
47
+ Provides-Extra: api
48
+ Provides-Extra: chroma
49
+ Provides-Extra: s3
50
+ Provides-Extra: ui
51
+ Description-Content-Type: text/markdown
52
+
53
+ # pydantic-rag-agent
54
+
55
+ A retrieval-augmented generation (RAG) agent built on [Pydantic](https://docs.pydantic.dev/)
56
+ and managed with [uv](https://docs.astral.sh/uv/).
57
+
58
+ > **Status:** feature-complete for a local, single-user deployment. M0–M5 are done and
59
+ > M6 is closed apart from OPS-1 (instrumentation), which is deliberately out of scope.
60
+ > Ingestion, retrieval, the agent, the API, the CLI and the Streamlit UI all work; the
61
+ > suite runs offline at 92% branch coverage. `main` is the state described in
62
+ > [`docs/overview.md`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/overview.md#current-state); the ordered plan behind it is in
63
+ > [`docs/features/`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/features/README.md) and
64
+ > [`docs/roadmap.md`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/roadmap.md).
65
+
66
+ ## Why uv?
67
+
68
+ Dependency resolution and virtualenv handling live in one fast tool, and `uv.lock`
69
+ pins the exact graph so your CI and your laptop agree on what "it works" means.
70
+
71
+ ## Documentation
72
+
73
+ Full documentation lives in [`docs/`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/README.md) — start with the
74
+ [documentation index](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/README.md) or the [project overview](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/overview.md).
75
+ Design rationale is recorded as [decision records](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/decisions/README.md).
76
+
77
+ Coding agents should read [`AGENTS.md`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/AGENTS.md) first.
78
+
79
+ ## Requirements
80
+
81
+ - [uv](https://docs.astral.sh/uv/getting-started/installation/) 0.13 or newer
82
+ - Python 3.11+ — uv will fetch and manage the interpreter for you if needed
83
+
84
+ ## Install
85
+
86
+ ```bash
87
+ uv add "pydantic-rag-agent" # core: agent, loaders, CLI, in-memory store
88
+ uv add "pydantic-rag-agent[chroma]" # plus the default persistent store
89
+ uv add "pydantic-rag-agent[chroma,ui]" # plus the Streamlit UI
90
+ uv add "pydantic-rag-agent[chroma,api]" # plus the FastAPI integration
91
+ uv add "pydantic-rag-agent[chroma,s3]" # plus originals in a bucket
92
+ uv add "pydantic-rag-agent[all]" # everything
93
+ ```
94
+
95
+ The core install has no vector database: it runs with the in-memory store, which is fine
96
+ for a script that ingests and asks in one go. Anything the agent does not need at import
97
+ time is an extra, and a missing one tells you which to install.
98
+
99
+ > **Not on PyPI yet.** The first release is milestone 7 — see
100
+ > [`docs/features/`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/features/README.md) and
101
+ > [ADR 0013](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/decisions/0013-packaging-and-release.md). Until then, install from the
102
+ > repository as below.
103
+
104
+ As a library, from the repository today (and from PyPI once published):
105
+
106
+ ```python
107
+ from pydantic_rag_agent import RagAgent
108
+
109
+ agent = RagAgent.from_env()
110
+ agent.ingest_sync("./docs")
111
+ print(agent.ask_sync("How long are backups retained?").text)
112
+ ```
113
+
114
+ The async methods (`await agent.ask(...)`, `async for update in agent.stream(...)`) are
115
+ what a web app wants; the sync helpers exist so a script does not have to become async to
116
+ ask one question. Answers carry citations back to the source document, including the
117
+ locator of the stored original (`file://` or `s3://`).
118
+
119
+ Already have a FastAPI app? Mount the router instead of running a second service:
120
+
121
+ ```python
122
+ from contextlib import asynccontextmanager
123
+
124
+ from fastapi import FastAPI
125
+
126
+ from pydantic_rag_agent import RagAgent
127
+ from pydantic_rag_agent.integrations.fastapi import create_router
128
+
129
+ agent = RagAgent.from_env()
130
+
131
+
132
+ @asynccontextmanager
133
+ async def lifespan(app: FastAPI):
134
+ await agent.check_index()
135
+ try:
136
+ yield
137
+ finally:
138
+ await agent.aclose()
139
+
140
+
141
+ app = FastAPI(lifespan=lifespan)
142
+ app.include_router(create_router(agent), prefix="/knowledge")
143
+ ```
144
+
145
+ The router brings the routes; your app keeps its lifespan, its auth and its shutdown.
146
+
147
+ Any OpenAI-speaking chat UI can be pointed at the agent instead of a bespoke frontend:
148
+
149
+ ```python
150
+ from pydantic_rag_agent.integrations.fastapi import create_openai_router
151
+
152
+ app.include_router(create_openai_router(agent, model_id="acme-knowledge"), prefix="/openai")
153
+ ```
154
+
155
+ Point the client at `https://your-host/openai/v1`. Requests are stateless (the client
156
+ sends the thread), caller-supplied system messages are ignored, and answers carry a
157
+ `Sources:` footer. `serve` already exposes the same route at `/v1`, so a chat UI can be
158
+ pointed at a running server without writing any code — `--openai-model-id` chooses the name
159
+ the client shows. See [ADR 0014](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/decisions/0014-openai-compatible-endpoint.md).
160
+
161
+ ## Getting started from the repository
162
+
163
+ ```bash
164
+ # Clone and enter the project
165
+ git clone git@github.com:hanku4u/pydantic-rag-agent.git
166
+ cd pydantic-rag-agent
167
+
168
+ # Create .venv and install the project plus its dependencies
169
+ uv sync
170
+
171
+ # Provide the one credential: chat, captions, and embeddings all use it
172
+ cp .env.example .env
173
+ # then edit .env and set OPENROUTER_API_KEY
174
+
175
+ # Index and ask — the agent runs in this process, no server needed
176
+ uv run pydantic-rag-agent ingest ./docs
177
+ uv run pydantic-rag-agent ask "How long are backups retained?"
178
+
179
+ # Optional: the API and web UI together
180
+ uv run pydantic-rag-agent dev
181
+ ```
182
+
183
+ The terminal answer streams and ends with a table of the sources it cited. The chat UI
184
+ from `dev` is at <http://127.0.0.1:8501>. `--api-url` makes any command talk to a running
185
+ server instead of building the agent locally.
186
+
187
+ ## Day-to-day commands
188
+
189
+ | Task | Command |
190
+ | --- | --- |
191
+ | Install or refresh dependencies | `uv sync` |
192
+ | Add a runtime dependency | `uv add <package>` |
193
+ | Add a dev-only dependency | `uv add --dev <package>` |
194
+ | Remove a dependency | `uv remove <package>` |
195
+ | Run a command inside the venv | `uv run <command>` |
196
+ | Run a script without installing it | `uv run path/to/script.py` |
197
+
198
+ ## Project layout
199
+
200
+ ```text
201
+ pydantic-rag-agent/
202
+ ├── pyproject.toml # project metadata, dependencies, CLI entry point
203
+ ├── uv.lock # exact resolved versions — commit this
204
+ ├── .python-version # interpreter uv should use
205
+ ├── AGENTS.md # orientation for coding agents
206
+ ├── docs/ # design, backlog, decisions — start at docs/README.md
207
+ ├── src/
208
+ │ └── pydantic_rag_agent/
209
+ │ ├── __init__.py # package marker, no import-time side effects
210
+ │ └── cli.py # command-line entry point (`main`)
211
+ └── README.md
212
+ ```
213
+
214
+ The `src/` layout keeps the package importable from an installed build rather
215
+ than by accident from the working directory, which is what makes
216
+ `uv run pytest` behave the same as a real install.
217
+
218
+ ## Configuration
219
+
220
+ Settings are a tree of six nodes — provider, embeddings, vector store, storage,
221
+ ingestion, agent — read from `PRAGENT_*` environment variables via `pydantic-settings`.
222
+ Nesting is addressed with a double underscore: `PRAGENT_PROVIDER__MODEL`,
223
+ `PRAGENT_AGENT__TOP_K`. Each node can also be constructed in code, which is how the
224
+ library is used.
225
+
226
+ Credentials keep their conventional names (`OPENROUTER_API_KEY`) and are never read from
227
+ a committed file. Every variable, its default, and the mapping from the pre-0.1.0 flat
228
+ names are in [`docs/reference/configuration.md`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/reference/configuration.md).
229
+
230
+ The `.gitignore` ignores `.env` and any `.env.*` file except `.env.example`.
231
+
232
+ ## Contributing
233
+
234
+ 1. `uv sync` to get a working environment.
235
+ 2. Pick a feature ID from the [backlog](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/features/README.md) and reference it in
236
+ your commit subject.
237
+ 3. Add tests under `tests/` next to the module they cover.
238
+ 4. `uv run pytest` before opening a pull request.
239
+
240
+ ## License
241
+
242
+ [MIT](https://github.com/hanku4u/pydantic-rag-agent/blob/main/LICENSE). Use it, fork it, ship it — just keep the copyright notice.
243
+
244
+ The dependency stack is deliberately permissive end to end; the one AGPL package that
245
+ previously blocked this was replaced. See
246
+ [`docs/reference/dependencies.md`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/reference/dependencies.md) for the details, and
247
+ [ADR 0007](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/decisions/0007-mit-licence-and-pypdfium2.md) for the reasoning.
@@ -0,0 +1,195 @@
1
+ # pydantic-rag-agent
2
+
3
+ A retrieval-augmented generation (RAG) agent built on [Pydantic](https://docs.pydantic.dev/)
4
+ and managed with [uv](https://docs.astral.sh/uv/).
5
+
6
+ > **Status:** feature-complete for a local, single-user deployment. M0–M5 are done and
7
+ > M6 is closed apart from OPS-1 (instrumentation), which is deliberately out of scope.
8
+ > Ingestion, retrieval, the agent, the API, the CLI and the Streamlit UI all work; the
9
+ > suite runs offline at 92% branch coverage. `main` is the state described in
10
+ > [`docs/overview.md`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/overview.md#current-state); the ordered plan behind it is in
11
+ > [`docs/features/`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/features/README.md) and
12
+ > [`docs/roadmap.md`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/roadmap.md).
13
+
14
+ ## Why uv?
15
+
16
+ Dependency resolution and virtualenv handling live in one fast tool, and `uv.lock`
17
+ pins the exact graph so your CI and your laptop agree on what "it works" means.
18
+
19
+ ## Documentation
20
+
21
+ Full documentation lives in [`docs/`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/README.md) — start with the
22
+ [documentation index](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/README.md) or the [project overview](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/overview.md).
23
+ Design rationale is recorded as [decision records](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/decisions/README.md).
24
+
25
+ Coding agents should read [`AGENTS.md`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/AGENTS.md) first.
26
+
27
+ ## Requirements
28
+
29
+ - [uv](https://docs.astral.sh/uv/getting-started/installation/) 0.13 or newer
30
+ - Python 3.11+ — uv will fetch and manage the interpreter for you if needed
31
+
32
+ ## Install
33
+
34
+ ```bash
35
+ uv add "pydantic-rag-agent" # core: agent, loaders, CLI, in-memory store
36
+ uv add "pydantic-rag-agent[chroma]" # plus the default persistent store
37
+ uv add "pydantic-rag-agent[chroma,ui]" # plus the Streamlit UI
38
+ uv add "pydantic-rag-agent[chroma,api]" # plus the FastAPI integration
39
+ uv add "pydantic-rag-agent[chroma,s3]" # plus originals in a bucket
40
+ uv add "pydantic-rag-agent[all]" # everything
41
+ ```
42
+
43
+ The core install has no vector database: it runs with the in-memory store, which is fine
44
+ for a script that ingests and asks in one go. Anything the agent does not need at import
45
+ time is an extra, and a missing one tells you which to install.
46
+
47
+ > **Not on PyPI yet.** The first release is milestone 7 — see
48
+ > [`docs/features/`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/features/README.md) and
49
+ > [ADR 0013](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/decisions/0013-packaging-and-release.md). Until then, install from the
50
+ > repository as below.
51
+
52
+ As a library, from the repository today (and from PyPI once published):
53
+
54
+ ```python
55
+ from pydantic_rag_agent import RagAgent
56
+
57
+ agent = RagAgent.from_env()
58
+ agent.ingest_sync("./docs")
59
+ print(agent.ask_sync("How long are backups retained?").text)
60
+ ```
61
+
62
+ The async methods (`await agent.ask(...)`, `async for update in agent.stream(...)`) are
63
+ what a web app wants; the sync helpers exist so a script does not have to become async to
64
+ ask one question. Answers carry citations back to the source document, including the
65
+ locator of the stored original (`file://` or `s3://`).
66
+
67
+ Already have a FastAPI app? Mount the router instead of running a second service:
68
+
69
+ ```python
70
+ from contextlib import asynccontextmanager
71
+
72
+ from fastapi import FastAPI
73
+
74
+ from pydantic_rag_agent import RagAgent
75
+ from pydantic_rag_agent.integrations.fastapi import create_router
76
+
77
+ agent = RagAgent.from_env()
78
+
79
+
80
+ @asynccontextmanager
81
+ async def lifespan(app: FastAPI):
82
+ await agent.check_index()
83
+ try:
84
+ yield
85
+ finally:
86
+ await agent.aclose()
87
+
88
+
89
+ app = FastAPI(lifespan=lifespan)
90
+ app.include_router(create_router(agent), prefix="/knowledge")
91
+ ```
92
+
93
+ The router brings the routes; your app keeps its lifespan, its auth and its shutdown.
94
+
95
+ Any OpenAI-speaking chat UI can be pointed at the agent instead of a bespoke frontend:
96
+
97
+ ```python
98
+ from pydantic_rag_agent.integrations.fastapi import create_openai_router
99
+
100
+ app.include_router(create_openai_router(agent, model_id="acme-knowledge"), prefix="/openai")
101
+ ```
102
+
103
+ Point the client at `https://your-host/openai/v1`. Requests are stateless (the client
104
+ sends the thread), caller-supplied system messages are ignored, and answers carry a
105
+ `Sources:` footer. `serve` already exposes the same route at `/v1`, so a chat UI can be
106
+ pointed at a running server without writing any code — `--openai-model-id` chooses the name
107
+ the client shows. See [ADR 0014](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/decisions/0014-openai-compatible-endpoint.md).
108
+
109
+ ## Getting started from the repository
110
+
111
+ ```bash
112
+ # Clone and enter the project
113
+ git clone git@github.com:hanku4u/pydantic-rag-agent.git
114
+ cd pydantic-rag-agent
115
+
116
+ # Create .venv and install the project plus its dependencies
117
+ uv sync
118
+
119
+ # Provide the one credential: chat, captions, and embeddings all use it
120
+ cp .env.example .env
121
+ # then edit .env and set OPENROUTER_API_KEY
122
+
123
+ # Index and ask — the agent runs in this process, no server needed
124
+ uv run pydantic-rag-agent ingest ./docs
125
+ uv run pydantic-rag-agent ask "How long are backups retained?"
126
+
127
+ # Optional: the API and web UI together
128
+ uv run pydantic-rag-agent dev
129
+ ```
130
+
131
+ The terminal answer streams and ends with a table of the sources it cited. The chat UI
132
+ from `dev` is at <http://127.0.0.1:8501>. `--api-url` makes any command talk to a running
133
+ server instead of building the agent locally.
134
+
135
+ ## Day-to-day commands
136
+
137
+ | Task | Command |
138
+ | --- | --- |
139
+ | Install or refresh dependencies | `uv sync` |
140
+ | Add a runtime dependency | `uv add <package>` |
141
+ | Add a dev-only dependency | `uv add --dev <package>` |
142
+ | Remove a dependency | `uv remove <package>` |
143
+ | Run a command inside the venv | `uv run <command>` |
144
+ | Run a script without installing it | `uv run path/to/script.py` |
145
+
146
+ ## Project layout
147
+
148
+ ```text
149
+ pydantic-rag-agent/
150
+ ├── pyproject.toml # project metadata, dependencies, CLI entry point
151
+ ├── uv.lock # exact resolved versions — commit this
152
+ ├── .python-version # interpreter uv should use
153
+ ├── AGENTS.md # orientation for coding agents
154
+ ├── docs/ # design, backlog, decisions — start at docs/README.md
155
+ ├── src/
156
+ │ └── pydantic_rag_agent/
157
+ │ ├── __init__.py # package marker, no import-time side effects
158
+ │ └── cli.py # command-line entry point (`main`)
159
+ └── README.md
160
+ ```
161
+
162
+ The `src/` layout keeps the package importable from an installed build rather
163
+ than by accident from the working directory, which is what makes
164
+ `uv run pytest` behave the same as a real install.
165
+
166
+ ## Configuration
167
+
168
+ Settings are a tree of six nodes — provider, embeddings, vector store, storage,
169
+ ingestion, agent — read from `PRAGENT_*` environment variables via `pydantic-settings`.
170
+ Nesting is addressed with a double underscore: `PRAGENT_PROVIDER__MODEL`,
171
+ `PRAGENT_AGENT__TOP_K`. Each node can also be constructed in code, which is how the
172
+ library is used.
173
+
174
+ Credentials keep their conventional names (`OPENROUTER_API_KEY`) and are never read from
175
+ a committed file. Every variable, its default, and the mapping from the pre-0.1.0 flat
176
+ names are in [`docs/reference/configuration.md`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/reference/configuration.md).
177
+
178
+ The `.gitignore` ignores `.env` and any `.env.*` file except `.env.example`.
179
+
180
+ ## Contributing
181
+
182
+ 1. `uv sync` to get a working environment.
183
+ 2. Pick a feature ID from the [backlog](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/features/README.md) and reference it in
184
+ your commit subject.
185
+ 3. Add tests under `tests/` next to the module they cover.
186
+ 4. `uv run pytest` before opening a pull request.
187
+
188
+ ## License
189
+
190
+ [MIT](https://github.com/hanku4u/pydantic-rag-agent/blob/main/LICENSE). Use it, fork it, ship it — just keep the copyright notice.
191
+
192
+ The dependency stack is deliberately permissive end to end; the one AGPL package that
193
+ previously blocked this was replaced. See
194
+ [`docs/reference/dependencies.md`](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/reference/dependencies.md) for the details, and
195
+ [ADR 0007](https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/decisions/0007-mit-licence-and-pypdfium2.md) for the reasoning.
@@ -0,0 +1,138 @@
1
+ [project]
2
+ name = "pydantic-rag-agent"
3
+ version = "0.1.0"
4
+ description = "A RAG agent built on Pydantic."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ keywords = [
9
+ "rag",
10
+ "retrieval-augmented-generation",
11
+ "pydantic",
12
+ "pydantic-ai",
13
+ "llm",
14
+ "vector-search",
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Environment :: Console",
19
+ "Framework :: FastAPI",
20
+ "Framework :: Pydantic",
21
+ "Framework :: Pydantic :: 2",
22
+ "Intended Audience :: Developers",
23
+ "Operating System :: OS Independent",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Typing :: Typed",
27
+ "Topic :: Software Development :: Libraries :: Python Modules",
28
+ "Topic :: Text Processing :: Indexing",
29
+ ]
30
+ requires-python = ">=3.11"
31
+ dependencies = [
32
+ "httpx>=0.28.1",
33
+ "pillow>=13.0.0",
34
+ "pydantic>=2.14.1",
35
+ "pydantic-ai-slim[openai]>=2.61,<3",
36
+ "pydantic-settings>=2.16.1",
37
+ "pypdfium2>=5.14.0",
38
+ "python-docx>=1.2.0",
39
+ "python-dotenv>=1.2.4",
40
+ "python-pptx>=1.0.2",
41
+ "rich>=15.0.0",
42
+ "tiktoken>=0.14.0",
43
+ "typer>=0.27.3",
44
+ ]
45
+
46
+ [[project.authors]]
47
+ name = "Nick"
48
+ email = "98120512+hanku4u@users.noreply.github.com"
49
+
50
+ [project.optional-dependencies]
51
+ chroma = ["chromadb>=1.5.9"]
52
+ api = [
53
+ "fastapi>=0.162.0",
54
+ "python-multipart>=0.0.32",
55
+ "uvicorn[standard]>=0.54.0",
56
+ ]
57
+ ui = ["streamlit>=1.66.1"]
58
+ s3 = ["boto3>=1.35"]
59
+ all = ["pydantic-rag-agent[chroma,api,ui,s3]"]
60
+
61
+ [project.scripts]
62
+ pydantic-rag-agent = "pydantic_rag_agent.cli:main"
63
+
64
+ [project.urls]
65
+ Homepage = "https://github.com/hanku4u/pydantic-rag-agent"
66
+ Repository = "https://github.com/hanku4u/pydantic-rag-agent"
67
+ Documentation = "https://github.com/hanku4u/pydantic-rag-agent/blob/main/docs/README.md"
68
+ Issues = "https://github.com/hanku4u/pydantic-rag-agent/issues"
69
+
70
+ [build-system]
71
+ requires = ["uv_build>=0.13.1,<0.14.0"]
72
+ build-backend = "uv_build"
73
+
74
+ [dependency-groups]
75
+ dev = [
76
+ "mypy>=2.4.0",
77
+ "pytest>=9.1.1",
78
+ "pytest-asyncio>=1.4.0",
79
+ "pytest-cov>=7.1.0",
80
+ "ruff>=0.17.2",
81
+ "boto3>=1.35",
82
+ "chromadb>=1.5.9",
83
+ "fastapi>=0.162.0",
84
+ "python-multipart>=0.0.32",
85
+ "streamlit>=1.66.1",
86
+ "uvicorn[standard]>=0.54.0",
87
+ ]
88
+
89
+ [tool.ruff]
90
+ line-length = 100
91
+ target-version = "py311"
92
+
93
+ [tool.ruff.lint]
94
+ select = [
95
+ "E",
96
+ "F",
97
+ "I",
98
+ "UP",
99
+ "B",
100
+ "SIM",
101
+ ]
102
+
103
+ [tool.pytest.ini_options]
104
+ testpaths = ["tests"]
105
+ asyncio_mode = "auto"
106
+ pythonpath = ["tests"]
107
+ python_functions = [
108
+ "test_*",
109
+ "*_should_*",
110
+ ]
111
+
112
+ [tool.coverage.run]
113
+ source = ["pydantic_rag_agent"]
114
+ branch = true
115
+
116
+ [tool.coverage.report]
117
+ fail_under = 85
118
+ exclude_lines = [
119
+ "pragma: no cover",
120
+ "if TYPE_CHECKING:",
121
+ "raise NotImplementedError",
122
+ "if __name__ == .__main__.:",
123
+ ]
124
+ omit = ["*/ui/*"]
125
+
126
+ [tool.mypy]
127
+ python_version = "3.11"
128
+ disallow_untyped_defs = true
129
+ warn_unused_ignores = true
130
+ warn_redundant_casts = true
131
+ plugins = ["pydantic.mypy"]
132
+
133
+ [[tool.mypy.overrides]]
134
+ module = [
135
+ "pypdfium2",
136
+ "pypdfium2.*",
137
+ ]
138
+ ignore_missing_imports = true