llmstack-cli 0.2.0__tar.gz → 0.3.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 (101) hide show
  1. llmstack_cli-0.3.0/CHANGELOG.md +63 -0
  2. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/PKG-INFO +162 -48
  3. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/README.md +158 -47
  4. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/pyproject.toml +3 -3
  5. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/__init__.py +1 -1
  6. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/core/health.py +1 -1
  7. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/Dockerfile +3 -1
  8. llmstack_cli-0.3.0/src/llmstack/gateway/cache.py +187 -0
  9. llmstack_cli-0.3.0/src/llmstack/gateway/circuit_breaker.py +177 -0
  10. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/main.py +28 -5
  11. llmstack_cli-0.3.0/src/llmstack/gateway/middleware/logging.py +114 -0
  12. llmstack_cli-0.3.0/src/llmstack/gateway/middleware/rate_limit.py +204 -0
  13. llmstack_cli-0.3.0/src/llmstack/gateway/proxy.py +110 -0
  14. llmstack_cli-0.3.0/src/llmstack/gateway/rag/pipeline.py +188 -0
  15. llmstack_cli-0.3.0/src/llmstack/gateway/rag/store.py +242 -0
  16. llmstack_cli-0.3.0/src/llmstack/gateway/routes/chat.py +51 -0
  17. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/routes/health.py +31 -5
  18. llmstack_cli-0.3.0/src/llmstack/gateway/routes/rag.py +137 -0
  19. llmstack_cli-0.3.0/tests/unit/__init__.py +0 -0
  20. llmstack_cli-0.3.0/tests/unit/test_cache.py +83 -0
  21. llmstack_cli-0.3.0/tests/unit/test_circuit_breaker.py +136 -0
  22. llmstack_cli-0.3.0/tests/unit/test_rag_pipeline.py +50 -0
  23. llmstack_cli-0.3.0/tests/unit/test_rag_store.py +79 -0
  24. llmstack_cli-0.3.0/tests/unit/test_rate_limit.py +72 -0
  25. llmstack_cli-0.2.0/CHANGELOG.md +0 -29
  26. llmstack_cli-0.2.0/src/llmstack/gateway/proxy.py +0 -58
  27. llmstack_cli-0.2.0/src/llmstack/gateway/routes/chat.py +0 -27
  28. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  29. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  30. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  31. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/.github/SECURITY.md +0 -0
  32. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/.github/workflows/ci.yml +0 -0
  33. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/.github/workflows/release.yml +0 -0
  34. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/.gitignore +0 -0
  35. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/CONTRIBUTING.md +0 -0
  36. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/LICENSE +0 -0
  37. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/Makefile +0 -0
  38. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/assets/social-preview.png +0 -0
  39. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/demo.gif +0 -0
  40. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/demo.tape +0 -0
  41. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/examples/output.txt +0 -0
  42. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/__main__.py +0 -0
  43. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/cli/__init__.py +0 -0
  44. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/cli/app.py +0 -0
  45. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/__init__.py +0 -0
  46. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/chat.py +0 -0
  47. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/doctor.py +0 -0
  48. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/down.py +0 -0
  49. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/export.py +0 -0
  50. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/init.py +0 -0
  51. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/logs.py +0 -0
  52. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/status.py +0 -0
  53. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/up.py +0 -0
  54. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/cli/console.py +0 -0
  55. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/config/__init__.py +0 -0
  56. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/config/loader.py +0 -0
  57. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/config/presets/__init__.py +0 -0
  58. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/config/presets/agent.py +0 -0
  59. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/config/presets/chat.py +0 -0
  60. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/config/presets/rag.py +0 -0
  61. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/config/schema.py +0 -0
  62. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/core/__init__.py +0 -0
  63. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/core/hardware.py +0 -0
  64. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/core/resolver.py +0 -0
  65. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/core/stack.py +0 -0
  66. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/docker/__init__.py +0 -0
  67. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/docker/manager.py +0 -0
  68. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/__init__.py +0 -0
  69. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/middleware/__init__.py +0 -0
  70. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/middleware/auth.py +0 -0
  71. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/middleware/metrics.py +0 -0
  72. {llmstack_cli-0.2.0/src/llmstack/gateway/routes → llmstack_cli-0.3.0/src/llmstack/gateway/rag}/__init__.py +0 -0
  73. {llmstack_cli-0.2.0/src/llmstack/plugins → llmstack_cli-0.3.0/src/llmstack/gateway/routes}/__init__.py +0 -0
  74. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/routes/embeddings.py +0 -0
  75. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/routes/models.py +0 -0
  76. {llmstack_cli-0.2.0/src/llmstack/services → llmstack_cli-0.3.0/src/llmstack/plugins}/__init__.py +0 -0
  77. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/plugins/loader.py +0 -0
  78. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/plugins/spec.py +0 -0
  79. {llmstack_cli-0.2.0/src/llmstack/services/cache → llmstack_cli-0.3.0/src/llmstack/services}/__init__.py +0 -0
  80. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/services/base.py +0 -0
  81. {llmstack_cli-0.2.0/src/llmstack/services/embeddings → llmstack_cli-0.3.0/src/llmstack/services/cache}/__init__.py +0 -0
  82. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/services/cache/redis.py +0 -0
  83. {llmstack_cli-0.2.0/src/llmstack/services/gateway → llmstack_cli-0.3.0/src/llmstack/services/embeddings}/__init__.py +0 -0
  84. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/services/embeddings/tei.py +0 -0
  85. {llmstack_cli-0.2.0/src/llmstack/services/inference → llmstack_cli-0.3.0/src/llmstack/services/gateway}/__init__.py +0 -0
  86. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/services/gateway/service.py +0 -0
  87. {llmstack_cli-0.2.0/src/llmstack/services/observe → llmstack_cli-0.3.0/src/llmstack/services/inference}/__init__.py +0 -0
  88. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/services/inference/ollama.py +0 -0
  89. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/services/inference/vllm.py +0 -0
  90. {llmstack_cli-0.2.0/src/llmstack/services/vectordb → llmstack_cli-0.3.0/src/llmstack/services/observe}/__init__.py +0 -0
  91. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/services/observe/prometheus.py +0 -0
  92. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/services/registry.py +0 -0
  93. {llmstack_cli-0.2.0/tests → llmstack_cli-0.3.0/src/llmstack/services/vectordb}/__init__.py +0 -0
  94. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/src/llmstack/services/vectordb/qdrant.py +0 -0
  95. {llmstack_cli-0.2.0/tests/unit → llmstack_cli-0.3.0/tests}/__init__.py +0 -0
  96. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/tests/unit/test_config.py +0 -0
  97. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/tests/unit/test_export.py +0 -0
  98. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/tests/unit/test_gateway.py +0 -0
  99. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/tests/unit/test_hardware.py +0 -0
  100. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/tests/unit/test_resolver.py +0 -0
  101. {llmstack_cli-0.2.0 → llmstack_cli-0.3.0}/tests/unit/test_services.py +0 -0
@@ -0,0 +1,63 @@
1
+ # Changelog
2
+
3
+ ## [0.3.0] - 2026-05-07
4
+
5
+ ### Added
6
+ - **RAG Pipeline** — real retrieval-augmented generation with Qdrant
7
+ - `POST /v1/rag/ingest` — chunk, embed, and store documents in Qdrant
8
+ - `POST /v1/rag/query` — semantic search + LLM generation with source citations
9
+ - `DELETE /v1/rag/documents/{source}` — delete documents by source
10
+ - `GET /v1/rag/status` — collection statistics
11
+ - Streaming support for RAG queries via SSE
12
+ - **Semantic Response Cache** — Redis-backed LLM response caching
13
+ - SHA-256 hash of (model + messages) for deterministic cache keys
14
+ - Only caches low-temperature requests (≤0.1) for correctness
15
+ - TTL-based expiration with configurable duration
16
+ - Cache hit/miss metrics exposed in `/healthz`
17
+ - `X-Cache: HIT/MISS` response headers
18
+ - **Token Bucket Rate Limiter** — Redis-backed with Lua script for atomicity
19
+ - Configurable via `rate_limit` in llmstack.yaml (e.g., `100/min`, `10/sec`)
20
+ - Per-API-key rate limiting with IP fallback
21
+ - In-memory fallback when Redis is unavailable
22
+ - Standard `X-RateLimit-*` and `Retry-After` headers
23
+ - Atomic Lua script prevents race conditions in distributed setup
24
+ - **Circuit Breaker** — resilience pattern for inference backend
25
+ - Three-state machine: CLOSED → OPEN → HALF_OPEN → CLOSED
26
+ - Exponential backoff on recovery timeout (capped)
27
+ - Fail-fast with `503 Service Unavailable` when circuit is open
28
+ - Metrics exposed in `/healthz` (state, failure count, rejections)
29
+ - **Structured Logging** — JSON request logs with correlation IDs
30
+ - `X-Request-ID` header propagation
31
+ - Per-request structured JSON with method, path, status, duration, client IP
32
+ - Configurable log level and format (JSON / text)
33
+ - Token usage extraction from inference responses into Prometheus metrics
34
+ - Redis health check in `/healthz` endpoint
35
+ - 50 new unit tests (95 total) covering cache, circuit breaker, rate limiter, RAG
36
+
37
+ ## [0.2.0] - 2026-05-07
38
+
39
+ ### Added
40
+ - `llmstack chat` — interactive terminal chat with streaming responses
41
+ - `llmstack export` — generate standalone docker-compose.yml from llmstack.yaml
42
+ - GitHub issue templates, PR template, security policy
43
+
44
+ ### Fixed
45
+ - Gateway Docker image now builds locally (no longer requires ghcr.io)
46
+ - Prometheus and Grafana configs are written to disk before container start
47
+ - Generated API keys persist to llmstack.yaml across restarts
48
+ - Clear error messages for port conflicts
49
+
50
+ ## [0.1.0] - 2026-05-07
51
+
52
+ ### Added
53
+ - CLI with `init`, `up`, `down`, `status`, `logs`, `doctor` commands
54
+ - Auto hardware detection (NVIDIA, Apple Silicon, CPU)
55
+ - Smart backend resolver (auto-picks Ollama or vLLM)
56
+ - Services: Ollama, vLLM, Qdrant, Redis, TEI (Text Embeddings Inference)
57
+ - API Gateway: OpenAI-compatible proxy with auth, rate limiting, SSE streaming
58
+ - Prometheus + Grafana observability with pre-provisioned dashboard
59
+ - Plugin system via Python entry_points
60
+ - Presets: `chat`, `rag`, `agent`
61
+ - Pydantic v2 config schema (`llmstack.yaml`)
62
+ - Docker SDK orchestration (no docker-compose dependency)
63
+ - CI/CD: GitHub Actions for lint/test and PyPI release
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llmstack-cli
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: One command. Full LLM stack. Zero config.
5
5
  Author: mara-werils
6
6
  License-Expression: Apache-2.0
@@ -22,13 +22,16 @@ Requires-Dist: pyyaml>=6.0
22
22
  Requires-Dist: rich>=13.0
23
23
  Requires-Dist: typer>=0.12
24
24
  Provides-Extra: dev
25
+ Requires-Dist: fakeredis>=2.21; extra == 'dev'
25
26
  Requires-Dist: fastapi>=0.115; extra == 'dev'
26
27
  Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
27
28
  Requires-Dist: pytest>=8.0; extra == 'dev'
29
+ Requires-Dist: redis>=5.0; extra == 'dev'
28
30
  Requires-Dist: ruff>=0.4; extra == 'dev'
29
31
  Requires-Dist: starlette>=0.40; extra == 'dev'
30
32
  Provides-Extra: gateway
31
33
  Requires-Dist: fastapi>=0.115; extra == 'gateway'
34
+ Requires-Dist: redis>=5.0; extra == 'gateway'
32
35
  Requires-Dist: starlette>=0.40; extra == 'gateway'
33
36
  Requires-Dist: uvicorn[standard]>=0.30; extra == 'gateway'
34
37
  Description-Content-Type: text/markdown
@@ -64,23 +67,35 @@ llmstack up
64
67
  That's it. You now have **7 services** running: inference, embeddings, vector DB, cache, API gateway, Prometheus, and Grafana.
65
68
 
66
69
  ```bash
67
- # Test it immediately
70
+ # Chat completion (OpenAI-compatible)
68
71
  curl http://localhost:8000/v1/chat/completions \
69
72
  -H "Authorization: Bearer YOUR_KEY" \
70
73
  -H "Content-Type: application/json" \
71
74
  -d '{"model":"llama3.2","messages":[{"role":"user","content":"Hello!"}]}'
75
+
76
+ # Ingest a document for RAG
77
+ curl http://localhost:8000/v1/rag/ingest \
78
+ -H "Authorization: Bearer YOUR_KEY" \
79
+ -H "Content-Type: application/json" \
80
+ -d '{"text":"LLMStack is an open-source tool for...","source":"docs.txt"}'
81
+
82
+ # Query with RAG
83
+ curl http://localhost:8000/v1/rag/query \
84
+ -H "Authorization: Bearer YOUR_KEY" \
85
+ -H "Content-Type: application/json" \
86
+ -d '{"question":"What is LLMStack?"}'
72
87
  ```
73
88
 
74
89
  Works with **any OpenAI-compatible client**: LangChain, LlamaIndex, Vercel AI SDK, openai-python.
75
90
 
76
91
  ## Who is this for?
77
92
 
78
- - **AI app developers** who want local inference without Docker boilerplate
93
+ - **AI app developers** who want local inference + RAG without Docker boilerplate
79
94
  - **Teams** who need an OpenAI-compatible API backed by local models
80
95
  - **Hobbyists** running LLMs locally who want vector search, caching, and monitoring out of the box
81
96
  - **Anyone** tired of writing 200+ lines of docker-compose.yml every time
82
97
 
83
- ## What you get
98
+ ## Architecture
84
99
 
85
100
  ```
86
101
  llmstack up
@@ -92,28 +107,85 @@ Works with **any OpenAI-compatible client**: LangChain, LlamaIndex, Vercel AI SD
92
107
  |
93
108
  +-------+-------+-------+-------+
94
109
  | | | | |
95
- +----v--+ +--v---+ +v-----+ +v----+ +v--------+
96
- |Qdrant | |Redis | |Ollama| | TEI | | Gateway |
97
- |Vector | |Cache | | or | |Embed| | FastAPI |
98
- | DB | | | | vLLM | | | | OpenAI |
99
- +-------+ +------+ +------+ +-----+ |compatible|
100
- :6333 :6379 :11434 :8002 +----+-----+
101
- |:8000
102
- +----v-----+
103
- |Prometheus |
104
- | + Grafana |
105
- +----------+
106
- :8080
110
+ +----v--+ +--v---+ +v-----+ +v----+ +v-----------+
111
+ |Qdrant | |Redis | |Ollama| | TEI | | Gateway |
112
+ |Vector | |Cache | | or | |Embed| | FastAPI |
113
+ | DB | |+ Rate| | vLLM | | | | + RAG |
114
+ | | | Limit| | | | | | + Cache |
115
+ +-------+ +------+ +------+ +-----+ | + Breaker |
116
+ :6333 :6379 :11434 :8002 | + Metrics |
117
+ +-----+------+
118
+ |:8000
119
+ +-----v------+
120
+ | Prometheus |
121
+ | + Grafana |
122
+ +------------+
123
+ :8080
107
124
  ```
108
125
 
109
- | Layer | Service | Default | Port |
110
- |-------|---------|---------|------|
111
- | Inference | Ollama / vLLM (auto) | llama3.2 | 11434 |
112
- | Embeddings | TEI / Ollama (auto) | bge-m3 | 8002 |
113
- | Vector DB | Qdrant | - | 6333 |
114
- | Cache | Redis | 256MB LRU | 6379 |
115
- | API Gateway | FastAPI (OpenAI-compatible) | auth + rate limit | 8000 |
116
- | Dashboard | Grafana + Prometheus | pre-built panels | 8080 |
126
+ | Layer | Service | What it does | Port |
127
+ |-------|---------|-------------|------|
128
+ | Inference | Ollama / vLLM (auto) | LLM chat completions | 11434 |
129
+ | Embeddings | TEI / Ollama (auto) | Text embeddings for RAG | 8002 |
130
+ | Vector DB | Qdrant | Document storage + semantic search | 6333 |
131
+ | Cache | Redis | Response cache + rate limit state | 6379 |
132
+ | API Gateway | FastAPI | Routing, auth, caching, RAG, circuit breaker | 8000 |
133
+ | Dashboard | Grafana + Prometheus | Request rate, latency, tokens, errors | 8080 |
134
+
135
+ ## Gateway Features
136
+
137
+ The gateway is not a simple proxy — it's a production-grade API layer:
138
+
139
+ ### Semantic Response Cache (Redis)
140
+ ```
141
+ Request → SHA-256(model + messages) → Redis lookup
142
+ HIT → Return cached response (< 1ms)
143
+ MISS → Forward to inference → Cache result → Return
144
+ ```
145
+ - Only caches deterministic requests (temperature <= 0.1)
146
+ - TTL-based expiration (default: 1 hour)
147
+ - `X-Cache: HIT/MISS` response headers
148
+ - Cache stats in `/healthz`
149
+
150
+ ### Token Bucket Rate Limiter (Redis + Lua)
151
+ ```
152
+ Request → Extract API key/IP → Redis EVALSHA (atomic Lua) → Allow/Reject
153
+ ```
154
+ - Configurable: `100/min`, `10/sec`, `3600/hour`
155
+ - Per-API-key rate limiting with IP fallback
156
+ - Atomic Lua script prevents race conditions
157
+ - In-memory fallback if Redis is unavailable
158
+ - Standard `X-RateLimit-*` and `Retry-After` headers
159
+
160
+ ### Circuit Breaker (Inference Resilience)
161
+ ```
162
+ CLOSED ──[5 failures]──> OPEN ──[timeout]──> HALF_OPEN ──[success]──> CLOSED
163
+ | |
164
+ └──[reject fast] └──[failure]──> OPEN (backoff x2)
165
+ ```
166
+ - Prevents cascading failures when inference is down
167
+ - Exponential backoff on recovery timeout
168
+ - Fail-fast with `503 Service Unavailable`
169
+ - Metrics: state, failure count, rejections, time in state
170
+
171
+ ### RAG Pipeline (Qdrant + Embeddings)
172
+ ```
173
+ Ingest: Document → Chunk (512 words, 64 overlap) → Embed → Qdrant
174
+ Query: Question → Embed → Qdrant search → Build context → LLM generate
175
+ ```
176
+ - `POST /v1/rag/ingest` — chunk, embed, and store documents
177
+ - `POST /v1/rag/query` — semantic search + augmented generation
178
+ - Source citations in responses
179
+ - Streaming support via SSE
180
+ - Deterministic chunk IDs (deduplication)
181
+
182
+ ### Structured Logging
183
+ ```json
184
+ {"ts":"2026-05-07T14:23:01","level":"INFO","msg":"POST /v1/chat/completions 200 1234.5ms","request_id":"a1b2c3d4","method":"POST","path":"/v1/chat/completions","status":200,"duration_ms":1234.5,"client_ip":"10.0.0.1"}
185
+ ```
186
+ - `X-Request-ID` correlation headers
187
+ - JSON structured output for log aggregation
188
+ - Configurable level and format
117
189
 
118
190
  ## How it works
119
191
 
@@ -125,6 +197,7 @@ llmstack up # Boots services in order with health checks:
125
197
  # Qdrant -> Redis -> Inference -> Embeddings -> Gateway -> Metrics
126
198
 
127
199
  llmstack status # Shows health of all running services
200
+ llmstack chat # Interactive terminal chat with streaming
128
201
  llmstack logs ollama # Stream inference logs
129
202
  llmstack down # Stops everything
130
203
  ```
@@ -180,6 +253,32 @@ observe:
180
253
  dashboard_port: 8080
181
254
  ```
182
255
 
256
+ ## API Reference
257
+
258
+ ### OpenAI-compatible endpoints
259
+
260
+ | Endpoint | Method | Description |
261
+ |----------|--------|-------------|
262
+ | `/v1/chat/completions` | POST | Chat completion (streaming + non-streaming) |
263
+ | `/v1/embeddings` | POST | Text embeddings |
264
+ | `/v1/models` | GET | List available models |
265
+
266
+ ### RAG endpoints
267
+
268
+ | Endpoint | Method | Description |
269
+ |----------|--------|-------------|
270
+ | `/v1/rag/ingest` | POST | Ingest a document (chunk + embed + store) |
271
+ | `/v1/rag/query` | POST | Query with retrieval-augmented generation |
272
+ | `/v1/rag/documents/{source}` | DELETE | Delete documents by source |
273
+ | `/v1/rag/status` | GET | Collection statistics |
274
+
275
+ ### System endpoints
276
+
277
+ | Endpoint | Method | Description |
278
+ |----------|--------|-------------|
279
+ | `/healthz` | GET | Health check with circuit breaker + cache stats |
280
+ | `/metrics` | GET | Prometheus metrics |
281
+
183
282
  ## Interactive Chat
184
283
 
185
284
  ```bash
@@ -198,12 +297,8 @@ You: /clear
198
297
  Conversation cleared.
199
298
  ```
200
299
 
201
- Streaming responses, conversation history, works with any model in your stack.
202
-
203
300
  ## Export to Docker Compose
204
301
 
205
- Don't want to install llmstack? Generate a standalone `docker-compose.yml`:
206
-
207
302
  ```bash
208
303
  llmstack export
209
304
  # Exported 7 services to docker-compose.yml
@@ -218,10 +313,37 @@ Share the generated file with your team — no llmstack dependency required.
218
313
  from openai import OpenAI
219
314
 
220
315
  client = OpenAI(base_url="http://localhost:8000/v1", api_key="YOUR_KEY")
316
+
317
+ # Chat completion
221
318
  response = client.chat.completions.create(
222
319
  model="llama3.2",
223
320
  messages=[{"role": "user", "content": "Explain quantum computing"}]
224
321
  )
322
+
323
+ # Embeddings
324
+ embeddings = client.embeddings.create(
325
+ model="bge-m3",
326
+ input=["Hello world"]
327
+ )
328
+ ```
329
+
330
+ ```python
331
+ import httpx
332
+
333
+ # RAG: Ingest documents
334
+ httpx.post("http://localhost:8000/v1/rag/ingest", json={
335
+ "text": open("whitepaper.txt").read(),
336
+ "source": "whitepaper.txt",
337
+ }, headers={"Authorization": "Bearer YOUR_KEY"})
338
+
339
+ # RAG: Query
340
+ response = httpx.post("http://localhost:8000/v1/rag/query", json={
341
+ "question": "What are the key findings?",
342
+ "top_k": 5,
343
+ }, headers={"Authorization": "Bearer YOUR_KEY"})
344
+
345
+ print(response.json()["answer"])
346
+ print(response.json()["sources"])
225
347
  ```
226
348
 
227
349
  ## CLI
@@ -245,35 +367,24 @@ When `observe.metrics: true`, llmstack boots Prometheus + Grafana with a pre-bui
245
367
  - **Latency** p50 / p99 histograms
246
368
  - **Token throughput** (input + output)
247
369
  - **Error rate** (4xx / 5xx)
248
- - **Service health** (up/down)
370
+ - **Cache hit rate**
371
+ - **Circuit breaker state**
372
+ - **Rate limit rejections**
249
373
 
250
374
  Access at `http://localhost:8080` (login: admin / llmstack)
251
375
 
252
- ## Why not just Docker Compose?
253
-
254
- Here's what llmstack replaces:
255
-
256
- ```yaml
257
- # Without llmstack: ~200 lines of docker-compose.yml
258
- # You have to configure each service, write health checks,
259
- # set up networking, manage GPU passthrough, create Prometheus
260
- # scrape configs, provision Grafana dashboards...
261
-
262
- # With llmstack:
263
- llmstack init && llmstack up
264
- ```
265
-
266
376
  ## Comparison
267
377
 
268
378
  | | llmstack | Ollama | LocalAI | AnythingLLM | LiteLLM |
269
379
  |---|---|---|---|---|---|
270
- | One-command full stack | **Yes** | No (inference only) | No | Partial | No (proxy only) |
380
+ | One-command full stack | **Yes** | No | No | Partial | No |
381
+ | Built-in RAG pipeline | **Yes** | No | No | Bundled | No |
382
+ | Response caching | **Yes** | No | No | No | No |
383
+ | Circuit breaker | **Yes** | No | No | No | No |
384
+ | Rate limiting (Redis) | **Yes** | No | No | Yes | Yes |
271
385
  | Auto hardware detection | **Yes** | No | No | No | No |
272
386
  | OpenAI-compatible API | **Yes** | Yes | Yes | No | Yes |
273
387
  | Built-in vector DB | **Yes** | No | No | Bundled | No |
274
- | Built-in embeddings | **Yes** | No | No | Bundled | No |
275
- | Caching (Redis) | **Yes** | No | No | No | No |
276
- | Auth + rate limiting | **Yes** | No | No | Yes | Yes |
277
388
  | Observability dashboard | **Yes** | No | Partial | No | Partial |
278
389
  | Plugin ecosystem | **Yes** | No | No | No | No |
279
390
 
@@ -292,8 +403,11 @@ Create your own: implement `ServiceBase`, register via entry_points. See [CONTRI
292
403
 
293
404
  - **CLI**: [Typer](https://typer.tiangolo.com/) + [Rich](https://rich.readthedocs.io/)
294
405
  - **Config**: [Pydantic v2](https://docs.pydantic.dev/)
295
- - **Gateway**: [FastAPI](https://fastapi.tiangolo.com/)
406
+ - **Gateway**: [FastAPI](https://fastapi.tiangolo.com/) + Redis + Qdrant
296
407
  - **Containers**: [Docker SDK for Python](https://docker-py.readthedocs.io/)
408
+ - **Cache**: Redis with semantic hashing
409
+ - **Rate Limiting**: Token bucket with Redis Lua scripts
410
+ - **Resilience**: Circuit breaker with exponential backoff
297
411
  - **Metrics**: Prometheus + Grafana
298
412
 
299
413
  ## Requirements
@@ -29,23 +29,35 @@ llmstack up
29
29
  That's it. You now have **7 services** running: inference, embeddings, vector DB, cache, API gateway, Prometheus, and Grafana.
30
30
 
31
31
  ```bash
32
- # Test it immediately
32
+ # Chat completion (OpenAI-compatible)
33
33
  curl http://localhost:8000/v1/chat/completions \
34
34
  -H "Authorization: Bearer YOUR_KEY" \
35
35
  -H "Content-Type: application/json" \
36
36
  -d '{"model":"llama3.2","messages":[{"role":"user","content":"Hello!"}]}'
37
+
38
+ # Ingest a document for RAG
39
+ curl http://localhost:8000/v1/rag/ingest \
40
+ -H "Authorization: Bearer YOUR_KEY" \
41
+ -H "Content-Type: application/json" \
42
+ -d '{"text":"LLMStack is an open-source tool for...","source":"docs.txt"}'
43
+
44
+ # Query with RAG
45
+ curl http://localhost:8000/v1/rag/query \
46
+ -H "Authorization: Bearer YOUR_KEY" \
47
+ -H "Content-Type: application/json" \
48
+ -d '{"question":"What is LLMStack?"}'
37
49
  ```
38
50
 
39
51
  Works with **any OpenAI-compatible client**: LangChain, LlamaIndex, Vercel AI SDK, openai-python.
40
52
 
41
53
  ## Who is this for?
42
54
 
43
- - **AI app developers** who want local inference without Docker boilerplate
55
+ - **AI app developers** who want local inference + RAG without Docker boilerplate
44
56
  - **Teams** who need an OpenAI-compatible API backed by local models
45
57
  - **Hobbyists** running LLMs locally who want vector search, caching, and monitoring out of the box
46
58
  - **Anyone** tired of writing 200+ lines of docker-compose.yml every time
47
59
 
48
- ## What you get
60
+ ## Architecture
49
61
 
50
62
  ```
51
63
  llmstack up
@@ -57,28 +69,85 @@ Works with **any OpenAI-compatible client**: LangChain, LlamaIndex, Vercel AI SD
57
69
  |
58
70
  +-------+-------+-------+-------+
59
71
  | | | | |
60
- +----v--+ +--v---+ +v-----+ +v----+ +v--------+
61
- |Qdrant | |Redis | |Ollama| | TEI | | Gateway |
62
- |Vector | |Cache | | or | |Embed| | FastAPI |
63
- | DB | | | | vLLM | | | | OpenAI |
64
- +-------+ +------+ +------+ +-----+ |compatible|
65
- :6333 :6379 :11434 :8002 +----+-----+
66
- |:8000
67
- +----v-----+
68
- |Prometheus |
69
- | + Grafana |
70
- +----------+
71
- :8080
72
+ +----v--+ +--v---+ +v-----+ +v----+ +v-----------+
73
+ |Qdrant | |Redis | |Ollama| | TEI | | Gateway |
74
+ |Vector | |Cache | | or | |Embed| | FastAPI |
75
+ | DB | |+ Rate| | vLLM | | | | + RAG |
76
+ | | | Limit| | | | | | + Cache |
77
+ +-------+ +------+ +------+ +-----+ | + Breaker |
78
+ :6333 :6379 :11434 :8002 | + Metrics |
79
+ +-----+------+
80
+ |:8000
81
+ +-----v------+
82
+ | Prometheus |
83
+ | + Grafana |
84
+ +------------+
85
+ :8080
72
86
  ```
73
87
 
74
- | Layer | Service | Default | Port |
75
- |-------|---------|---------|------|
76
- | Inference | Ollama / vLLM (auto) | llama3.2 | 11434 |
77
- | Embeddings | TEI / Ollama (auto) | bge-m3 | 8002 |
78
- | Vector DB | Qdrant | - | 6333 |
79
- | Cache | Redis | 256MB LRU | 6379 |
80
- | API Gateway | FastAPI (OpenAI-compatible) | auth + rate limit | 8000 |
81
- | Dashboard | Grafana + Prometheus | pre-built panels | 8080 |
88
+ | Layer | Service | What it does | Port |
89
+ |-------|---------|-------------|------|
90
+ | Inference | Ollama / vLLM (auto) | LLM chat completions | 11434 |
91
+ | Embeddings | TEI / Ollama (auto) | Text embeddings for RAG | 8002 |
92
+ | Vector DB | Qdrant | Document storage + semantic search | 6333 |
93
+ | Cache | Redis | Response cache + rate limit state | 6379 |
94
+ | API Gateway | FastAPI | Routing, auth, caching, RAG, circuit breaker | 8000 |
95
+ | Dashboard | Grafana + Prometheus | Request rate, latency, tokens, errors | 8080 |
96
+
97
+ ## Gateway Features
98
+
99
+ The gateway is not a simple proxy — it's a production-grade API layer:
100
+
101
+ ### Semantic Response Cache (Redis)
102
+ ```
103
+ Request → SHA-256(model + messages) → Redis lookup
104
+ HIT → Return cached response (< 1ms)
105
+ MISS → Forward to inference → Cache result → Return
106
+ ```
107
+ - Only caches deterministic requests (temperature <= 0.1)
108
+ - TTL-based expiration (default: 1 hour)
109
+ - `X-Cache: HIT/MISS` response headers
110
+ - Cache stats in `/healthz`
111
+
112
+ ### Token Bucket Rate Limiter (Redis + Lua)
113
+ ```
114
+ Request → Extract API key/IP → Redis EVALSHA (atomic Lua) → Allow/Reject
115
+ ```
116
+ - Configurable: `100/min`, `10/sec`, `3600/hour`
117
+ - Per-API-key rate limiting with IP fallback
118
+ - Atomic Lua script prevents race conditions
119
+ - In-memory fallback if Redis is unavailable
120
+ - Standard `X-RateLimit-*` and `Retry-After` headers
121
+
122
+ ### Circuit Breaker (Inference Resilience)
123
+ ```
124
+ CLOSED ──[5 failures]──> OPEN ──[timeout]──> HALF_OPEN ──[success]──> CLOSED
125
+ | |
126
+ └──[reject fast] └──[failure]──> OPEN (backoff x2)
127
+ ```
128
+ - Prevents cascading failures when inference is down
129
+ - Exponential backoff on recovery timeout
130
+ - Fail-fast with `503 Service Unavailable`
131
+ - Metrics: state, failure count, rejections, time in state
132
+
133
+ ### RAG Pipeline (Qdrant + Embeddings)
134
+ ```
135
+ Ingest: Document → Chunk (512 words, 64 overlap) → Embed → Qdrant
136
+ Query: Question → Embed → Qdrant search → Build context → LLM generate
137
+ ```
138
+ - `POST /v1/rag/ingest` — chunk, embed, and store documents
139
+ - `POST /v1/rag/query` — semantic search + augmented generation
140
+ - Source citations in responses
141
+ - Streaming support via SSE
142
+ - Deterministic chunk IDs (deduplication)
143
+
144
+ ### Structured Logging
145
+ ```json
146
+ {"ts":"2026-05-07T14:23:01","level":"INFO","msg":"POST /v1/chat/completions 200 1234.5ms","request_id":"a1b2c3d4","method":"POST","path":"/v1/chat/completions","status":200,"duration_ms":1234.5,"client_ip":"10.0.0.1"}
147
+ ```
148
+ - `X-Request-ID` correlation headers
149
+ - JSON structured output for log aggregation
150
+ - Configurable level and format
82
151
 
83
152
  ## How it works
84
153
 
@@ -90,6 +159,7 @@ llmstack up # Boots services in order with health checks:
90
159
  # Qdrant -> Redis -> Inference -> Embeddings -> Gateway -> Metrics
91
160
 
92
161
  llmstack status # Shows health of all running services
162
+ llmstack chat # Interactive terminal chat with streaming
93
163
  llmstack logs ollama # Stream inference logs
94
164
  llmstack down # Stops everything
95
165
  ```
@@ -145,6 +215,32 @@ observe:
145
215
  dashboard_port: 8080
146
216
  ```
147
217
 
218
+ ## API Reference
219
+
220
+ ### OpenAI-compatible endpoints
221
+
222
+ | Endpoint | Method | Description |
223
+ |----------|--------|-------------|
224
+ | `/v1/chat/completions` | POST | Chat completion (streaming + non-streaming) |
225
+ | `/v1/embeddings` | POST | Text embeddings |
226
+ | `/v1/models` | GET | List available models |
227
+
228
+ ### RAG endpoints
229
+
230
+ | Endpoint | Method | Description |
231
+ |----------|--------|-------------|
232
+ | `/v1/rag/ingest` | POST | Ingest a document (chunk + embed + store) |
233
+ | `/v1/rag/query` | POST | Query with retrieval-augmented generation |
234
+ | `/v1/rag/documents/{source}` | DELETE | Delete documents by source |
235
+ | `/v1/rag/status` | GET | Collection statistics |
236
+
237
+ ### System endpoints
238
+
239
+ | Endpoint | Method | Description |
240
+ |----------|--------|-------------|
241
+ | `/healthz` | GET | Health check with circuit breaker + cache stats |
242
+ | `/metrics` | GET | Prometheus metrics |
243
+
148
244
  ## Interactive Chat
149
245
 
150
246
  ```bash
@@ -163,12 +259,8 @@ You: /clear
163
259
  Conversation cleared.
164
260
  ```
165
261
 
166
- Streaming responses, conversation history, works with any model in your stack.
167
-
168
262
  ## Export to Docker Compose
169
263
 
170
- Don't want to install llmstack? Generate a standalone `docker-compose.yml`:
171
-
172
264
  ```bash
173
265
  llmstack export
174
266
  # Exported 7 services to docker-compose.yml
@@ -183,10 +275,37 @@ Share the generated file with your team — no llmstack dependency required.
183
275
  from openai import OpenAI
184
276
 
185
277
  client = OpenAI(base_url="http://localhost:8000/v1", api_key="YOUR_KEY")
278
+
279
+ # Chat completion
186
280
  response = client.chat.completions.create(
187
281
  model="llama3.2",
188
282
  messages=[{"role": "user", "content": "Explain quantum computing"}]
189
283
  )
284
+
285
+ # Embeddings
286
+ embeddings = client.embeddings.create(
287
+ model="bge-m3",
288
+ input=["Hello world"]
289
+ )
290
+ ```
291
+
292
+ ```python
293
+ import httpx
294
+
295
+ # RAG: Ingest documents
296
+ httpx.post("http://localhost:8000/v1/rag/ingest", json={
297
+ "text": open("whitepaper.txt").read(),
298
+ "source": "whitepaper.txt",
299
+ }, headers={"Authorization": "Bearer YOUR_KEY"})
300
+
301
+ # RAG: Query
302
+ response = httpx.post("http://localhost:8000/v1/rag/query", json={
303
+ "question": "What are the key findings?",
304
+ "top_k": 5,
305
+ }, headers={"Authorization": "Bearer YOUR_KEY"})
306
+
307
+ print(response.json()["answer"])
308
+ print(response.json()["sources"])
190
309
  ```
191
310
 
192
311
  ## CLI
@@ -210,35 +329,24 @@ When `observe.metrics: true`, llmstack boots Prometheus + Grafana with a pre-bui
210
329
  - **Latency** p50 / p99 histograms
211
330
  - **Token throughput** (input + output)
212
331
  - **Error rate** (4xx / 5xx)
213
- - **Service health** (up/down)
332
+ - **Cache hit rate**
333
+ - **Circuit breaker state**
334
+ - **Rate limit rejections**
214
335
 
215
336
  Access at `http://localhost:8080` (login: admin / llmstack)
216
337
 
217
- ## Why not just Docker Compose?
218
-
219
- Here's what llmstack replaces:
220
-
221
- ```yaml
222
- # Without llmstack: ~200 lines of docker-compose.yml
223
- # You have to configure each service, write health checks,
224
- # set up networking, manage GPU passthrough, create Prometheus
225
- # scrape configs, provision Grafana dashboards...
226
-
227
- # With llmstack:
228
- llmstack init && llmstack up
229
- ```
230
-
231
338
  ## Comparison
232
339
 
233
340
  | | llmstack | Ollama | LocalAI | AnythingLLM | LiteLLM |
234
341
  |---|---|---|---|---|---|
235
- | One-command full stack | **Yes** | No (inference only) | No | Partial | No (proxy only) |
342
+ | One-command full stack | **Yes** | No | No | Partial | No |
343
+ | Built-in RAG pipeline | **Yes** | No | No | Bundled | No |
344
+ | Response caching | **Yes** | No | No | No | No |
345
+ | Circuit breaker | **Yes** | No | No | No | No |
346
+ | Rate limiting (Redis) | **Yes** | No | No | Yes | Yes |
236
347
  | Auto hardware detection | **Yes** | No | No | No | No |
237
348
  | OpenAI-compatible API | **Yes** | Yes | Yes | No | Yes |
238
349
  | Built-in vector DB | **Yes** | No | No | Bundled | No |
239
- | Built-in embeddings | **Yes** | No | No | Bundled | No |
240
- | Caching (Redis) | **Yes** | No | No | No | No |
241
- | Auth + rate limiting | **Yes** | No | No | Yes | Yes |
242
350
  | Observability dashboard | **Yes** | No | Partial | No | Partial |
243
351
  | Plugin ecosystem | **Yes** | No | No | No | No |
244
352
 
@@ -257,8 +365,11 @@ Create your own: implement `ServiceBase`, register via entry_points. See [CONTRI
257
365
 
258
366
  - **CLI**: [Typer](https://typer.tiangolo.com/) + [Rich](https://rich.readthedocs.io/)
259
367
  - **Config**: [Pydantic v2](https://docs.pydantic.dev/)
260
- - **Gateway**: [FastAPI](https://fastapi.tiangolo.com/)
368
+ - **Gateway**: [FastAPI](https://fastapi.tiangolo.com/) + Redis + Qdrant
261
369
  - **Containers**: [Docker SDK for Python](https://docker-py.readthedocs.io/)
370
+ - **Cache**: Redis with semantic hashing
371
+ - **Rate Limiting**: Token bucket with Redis Lua scripts
372
+ - **Resilience**: Circuit breaker with exponential backoff
262
373
  - **Metrics**: Prometheus + Grafana
263
374
 
264
375
  ## Requirements