llmstack-cli 0.1.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 (103) hide show
  1. llmstack_cli-0.3.0/.github/ISSUE_TEMPLATE/bug_report.yml +38 -0
  2. llmstack_cli-0.3.0/.github/ISSUE_TEMPLATE/feature_request.yml +23 -0
  3. llmstack_cli-0.3.0/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  4. llmstack_cli-0.3.0/.github/SECURITY.md +17 -0
  5. llmstack_cli-0.3.0/CHANGELOG.md +63 -0
  6. llmstack_cli-0.3.0/PKG-INFO +424 -0
  7. llmstack_cli-0.3.0/README.md +386 -0
  8. llmstack_cli-0.3.0/assets/social-preview.png +0 -0
  9. llmstack_cli-0.3.0/demo.gif +0 -0
  10. llmstack_cli-0.3.0/demo.tape +51 -0
  11. llmstack_cli-0.3.0/examples/output.txt +86 -0
  12. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/pyproject.toml +6 -3
  13. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/__init__.py +1 -1
  14. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/cli/app.py +18 -0
  15. llmstack_cli-0.3.0/src/llmstack/cli/commands/chat.py +104 -0
  16. llmstack_cli-0.3.0/src/llmstack/cli/commands/export.py +190 -0
  17. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/core/health.py +1 -1
  18. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/core/stack.py +12 -1
  19. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/docker/manager.py +23 -7
  20. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/Dockerfile +6 -2
  21. llmstack_cli-0.3.0/src/llmstack/gateway/cache.py +187 -0
  22. llmstack_cli-0.3.0/src/llmstack/gateway/circuit_breaker.py +177 -0
  23. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/main.py +28 -5
  24. llmstack_cli-0.3.0/src/llmstack/gateway/middleware/logging.py +114 -0
  25. llmstack_cli-0.3.0/src/llmstack/gateway/middleware/rate_limit.py +204 -0
  26. llmstack_cli-0.3.0/src/llmstack/gateway/proxy.py +110 -0
  27. llmstack_cli-0.3.0/src/llmstack/gateway/rag/pipeline.py +188 -0
  28. llmstack_cli-0.3.0/src/llmstack/gateway/rag/store.py +242 -0
  29. llmstack_cli-0.3.0/src/llmstack/gateway/routes/chat.py +51 -0
  30. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/routes/health.py +31 -5
  31. llmstack_cli-0.3.0/src/llmstack/gateway/routes/rag.py +137 -0
  32. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/services/gateway/service.py +16 -1
  33. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/services/observe/prometheus.py +76 -23
  34. llmstack_cli-0.3.0/tests/unit/__init__.py +0 -0
  35. llmstack_cli-0.3.0/tests/unit/test_cache.py +83 -0
  36. llmstack_cli-0.3.0/tests/unit/test_circuit_breaker.py +136 -0
  37. llmstack_cli-0.3.0/tests/unit/test_export.py +65 -0
  38. llmstack_cli-0.3.0/tests/unit/test_rag_pipeline.py +50 -0
  39. llmstack_cli-0.3.0/tests/unit/test_rag_store.py +79 -0
  40. llmstack_cli-0.3.0/tests/unit/test_rate_limit.py +72 -0
  41. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/tests/unit/test_services.py +21 -0
  42. llmstack_cli-0.1.0/CHANGELOG.md +0 -16
  43. llmstack_cli-0.1.0/PKG-INFO +0 -252
  44. llmstack_cli-0.1.0/README.md +0 -217
  45. llmstack_cli-0.1.0/src/llmstack/gateway/proxy.py +0 -58
  46. llmstack_cli-0.1.0/src/llmstack/gateway/routes/chat.py +0 -27
  47. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/.github/workflows/ci.yml +0 -0
  48. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/.github/workflows/release.yml +0 -0
  49. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/.gitignore +0 -0
  50. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/CONTRIBUTING.md +0 -0
  51. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/LICENSE +0 -0
  52. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/Makefile +0 -0
  53. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/__main__.py +0 -0
  54. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/cli/__init__.py +0 -0
  55. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/__init__.py +0 -0
  56. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/doctor.py +0 -0
  57. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/down.py +0 -0
  58. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/init.py +0 -0
  59. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/logs.py +0 -0
  60. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/status.py +0 -0
  61. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/cli/commands/up.py +0 -0
  62. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/cli/console.py +0 -0
  63. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/config/__init__.py +0 -0
  64. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/config/loader.py +0 -0
  65. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/config/presets/__init__.py +0 -0
  66. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/config/presets/agent.py +0 -0
  67. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/config/presets/chat.py +0 -0
  68. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/config/presets/rag.py +0 -0
  69. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/config/schema.py +0 -0
  70. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/core/__init__.py +0 -0
  71. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/core/hardware.py +0 -0
  72. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/core/resolver.py +0 -0
  73. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/docker/__init__.py +0 -0
  74. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/__init__.py +0 -0
  75. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/middleware/__init__.py +0 -0
  76. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/middleware/auth.py +0 -0
  77. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/middleware/metrics.py +0 -0
  78. {llmstack_cli-0.1.0/src/llmstack/gateway/routes → llmstack_cli-0.3.0/src/llmstack/gateway/rag}/__init__.py +0 -0
  79. {llmstack_cli-0.1.0/src/llmstack/plugins → llmstack_cli-0.3.0/src/llmstack/gateway/routes}/__init__.py +0 -0
  80. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/routes/embeddings.py +0 -0
  81. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/gateway/routes/models.py +0 -0
  82. {llmstack_cli-0.1.0/src/llmstack/services → llmstack_cli-0.3.0/src/llmstack/plugins}/__init__.py +0 -0
  83. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/plugins/loader.py +0 -0
  84. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/plugins/spec.py +0 -0
  85. {llmstack_cli-0.1.0/src/llmstack/services/cache → llmstack_cli-0.3.0/src/llmstack/services}/__init__.py +0 -0
  86. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/services/base.py +0 -0
  87. {llmstack_cli-0.1.0/src/llmstack/services/embeddings → llmstack_cli-0.3.0/src/llmstack/services/cache}/__init__.py +0 -0
  88. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/services/cache/redis.py +0 -0
  89. {llmstack_cli-0.1.0/src/llmstack/services/gateway → llmstack_cli-0.3.0/src/llmstack/services/embeddings}/__init__.py +0 -0
  90. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/services/embeddings/tei.py +0 -0
  91. {llmstack_cli-0.1.0/src/llmstack/services/inference → llmstack_cli-0.3.0/src/llmstack/services/gateway}/__init__.py +0 -0
  92. {llmstack_cli-0.1.0/src/llmstack/services/observe → llmstack_cli-0.3.0/src/llmstack/services/inference}/__init__.py +0 -0
  93. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/services/inference/ollama.py +0 -0
  94. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/services/inference/vllm.py +0 -0
  95. {llmstack_cli-0.1.0/src/llmstack/services/vectordb → llmstack_cli-0.3.0/src/llmstack/services/observe}/__init__.py +0 -0
  96. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/services/registry.py +0 -0
  97. {llmstack_cli-0.1.0/tests → llmstack_cli-0.3.0/src/llmstack/services/vectordb}/__init__.py +0 -0
  98. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/src/llmstack/services/vectordb/qdrant.py +0 -0
  99. {llmstack_cli-0.1.0/tests/unit → llmstack_cli-0.3.0/tests}/__init__.py +0 -0
  100. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/tests/unit/test_config.py +0 -0
  101. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/tests/unit/test_gateway.py +0 -0
  102. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/tests/unit/test_hardware.py +0 -0
  103. {llmstack_cli-0.1.0 → llmstack_cli-0.3.0}/tests/unit/test_resolver.py +0 -0
@@ -0,0 +1,38 @@
1
+ name: Bug Report
2
+ description: Report a bug or unexpected behavior
3
+ labels: ["bug"]
4
+ body:
5
+ - type: textarea
6
+ id: description
7
+ attributes:
8
+ label: What happened?
9
+ description: A clear description of the bug.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: reproduce
14
+ attributes:
15
+ label: Steps to reproduce
16
+ description: Minimal steps to reproduce the issue.
17
+ placeholder: |
18
+ 1. llmstack init --preset rag
19
+ 2. llmstack up
20
+ 3. ...
21
+ validations:
22
+ required: true
23
+ - type: textarea
24
+ id: expected
25
+ attributes:
26
+ label: Expected behavior
27
+ description: What did you expect to happen?
28
+ - type: textarea
29
+ id: environment
30
+ attributes:
31
+ label: Environment
32
+ description: Paste the output of `llmstack doctor`
33
+ render: shell
34
+ - type: input
35
+ id: version
36
+ attributes:
37
+ label: llmstack version
38
+ placeholder: "0.1.0"
@@ -0,0 +1,23 @@
1
+ name: Feature Request
2
+ description: Suggest a new feature or improvement
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: Problem
9
+ description: What problem does this solve? What's your use case?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: solution
14
+ attributes:
15
+ label: Proposed solution
16
+ description: How would you like this to work?
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: alternatives
21
+ attributes:
22
+ label: Alternatives considered
23
+ description: Any other approaches you've considered?
@@ -0,0 +1,17 @@
1
+ ## Summary
2
+
3
+ <!-- What does this PR do? -->
4
+
5
+ ## Changes
6
+
7
+ -
8
+
9
+ ## Test plan
10
+
11
+ - [ ] `make test` passes
12
+ - [ ] `make lint` passes
13
+ - [ ] Tested manually with `llmstack up`
14
+
15
+ ## Related issues
16
+
17
+ <!-- Fixes #123 -->
@@ -0,0 +1,17 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ If you discover a security vulnerability, please report it responsibly:
6
+
7
+ 1. **Do not** open a public issue
8
+ 2. Email: [open a private security advisory](https://github.com/mara-werils/llmstack/security/advisories/new)
9
+ 3. Include steps to reproduce and potential impact
10
+
11
+ We will respond within 48 hours and aim to release a fix within 7 days.
12
+
13
+ ## Supported Versions
14
+
15
+ | Version | Supported |
16
+ |---------|-----------|
17
+ | 0.1.x | Yes |
@@ -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
@@ -0,0 +1,424 @@
1
+ Metadata-Version: 2.4
2
+ Name: llmstack-cli
3
+ Version: 0.3.0
4
+ Summary: One command. Full LLM stack. Zero config.
5
+ Author: mara-werils
6
+ License-Expression: Apache-2.0
7
+ License-File: LICENSE
8
+ Keywords: ai,cli,docker,inference,llm,openai,rag
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
+ Requires-Python: >=3.11
17
+ Requires-Dist: docker>=7.0
18
+ Requires-Dist: httpx>=0.27
19
+ Requires-Dist: psutil>=5.9
20
+ Requires-Dist: pydantic>=2.0
21
+ Requires-Dist: pyyaml>=6.0
22
+ Requires-Dist: rich>=13.0
23
+ Requires-Dist: typer>=0.12
24
+ Provides-Extra: dev
25
+ Requires-Dist: fakeredis>=2.21; extra == 'dev'
26
+ Requires-Dist: fastapi>=0.115; extra == 'dev'
27
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
28
+ Requires-Dist: pytest>=8.0; extra == 'dev'
29
+ Requires-Dist: redis>=5.0; extra == 'dev'
30
+ Requires-Dist: ruff>=0.4; extra == 'dev'
31
+ Requires-Dist: starlette>=0.40; extra == 'dev'
32
+ Provides-Extra: gateway
33
+ Requires-Dist: fastapi>=0.115; extra == 'gateway'
34
+ Requires-Dist: redis>=5.0; extra == 'gateway'
35
+ Requires-Dist: starlette>=0.40; extra == 'gateway'
36
+ Requires-Dist: uvicorn[standard]>=0.30; extra == 'gateway'
37
+ Description-Content-Type: text/markdown
38
+
39
+ <p align="center">
40
+ <h1 align="center">llmstack</h1>
41
+ <p align="center"><strong>One command. Full LLM stack. Zero config.</strong></p>
42
+ <p align="center">Stop wiring Docker containers. Start building AI apps.</p>
43
+ </p>
44
+
45
+ <p align="center">
46
+ <a href="https://pypi.org/project/llmstack-cli/"><img src="https://img.shields.io/pypi/v/llmstack-cli?color=blue" alt="PyPI"></a>
47
+ <a href="https://github.com/mara-werils/llmstack/actions/workflows/ci.yml"><img src="https://github.com/mara-werils/llmstack/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
48
+ <a href="https://github.com/mara-werils/llmstack/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-green" alt="License"></a>
49
+ <a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.11+-blue" alt="Python"></a>
50
+ <a href="https://github.com/mara-werils/llmstack/stargazers"><img src="https://img.shields.io/github/stars/mara-werils/llmstack?style=social" alt="Stars"></a>
51
+ </p>
52
+
53
+ ---
54
+
55
+ <p align="center">
56
+ <img src="demo.gif" alt="llmstack demo" width="800">
57
+ </p>
58
+
59
+ ## Quick Start
60
+
61
+ ```bash
62
+ pip install llmstack-cli
63
+ llmstack init --preset rag
64
+ llmstack up
65
+ ```
66
+
67
+ That's it. You now have **7 services** running: inference, embeddings, vector DB, cache, API gateway, Prometheus, and Grafana.
68
+
69
+ ```bash
70
+ # Chat completion (OpenAI-compatible)
71
+ curl http://localhost:8000/v1/chat/completions \
72
+ -H "Authorization: Bearer YOUR_KEY" \
73
+ -H "Content-Type: application/json" \
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?"}'
87
+ ```
88
+
89
+ Works with **any OpenAI-compatible client**: LangChain, LlamaIndex, Vercel AI SDK, openai-python.
90
+
91
+ ## Who is this for?
92
+
93
+ - **AI app developers** who want local inference + RAG without Docker boilerplate
94
+ - **Teams** who need an OpenAI-compatible API backed by local models
95
+ - **Hobbyists** running LLMs locally who want vector search, caching, and monitoring out of the box
96
+ - **Anyone** tired of writing 200+ lines of docker-compose.yml every time
97
+
98
+ ## Architecture
99
+
100
+ ```
101
+ llmstack up
102
+ |
103
+ +---------v----------+
104
+ | Hardware Detect |
105
+ | NVIDIA / Apple / CPU|
106
+ +---------+----------+
107
+ |
108
+ +-------+-------+-------+-------+
109
+ | | | | |
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
124
+ ```
125
+
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
189
+
190
+ ## How it works
191
+
192
+ ```bash
193
+ llmstack init # Detects hardware, generates llmstack.yaml
194
+ # Picks optimal backend: vLLM for NVIDIA 16GB+, Ollama otherwise
195
+
196
+ llmstack up # Boots services in order with health checks:
197
+ # Qdrant -> Redis -> Inference -> Embeddings -> Gateway -> Metrics
198
+
199
+ llmstack status # Shows health of all running services
200
+ llmstack chat # Interactive terminal chat with streaming
201
+ llmstack logs ollama # Stream inference logs
202
+ llmstack down # Stops everything
203
+ ```
204
+
205
+ ## Auto hardware detection
206
+
207
+ | Your hardware | Backend | Why |
208
+ |---|---|---|
209
+ | NVIDIA GPU 16GB+ VRAM | vLLM | Max throughput, PagedAttention |
210
+ | NVIDIA GPU <16GB | Ollama | Lower memory overhead |
211
+ | Apple Silicon (M1-M4) | Ollama | Metal acceleration |
212
+ | CPU only | Ollama | GGUF quantized models |
213
+
214
+ ## Presets
215
+
216
+ ```bash
217
+ llmstack init --preset chat # Minimal: inference + cache + gateway
218
+ llmstack init --preset rag # + Qdrant + embeddings for RAG apps
219
+ llmstack init --preset agent # 70B model + 16K context + longer timeouts
220
+ ```
221
+
222
+ ## Configuration
223
+
224
+ One file: `llmstack.yaml`
225
+
226
+ ```yaml
227
+ version: "1"
228
+
229
+ models:
230
+ chat:
231
+ name: llama3.2
232
+ backend: auto # auto | ollama | vllm
233
+ context_length: 8192
234
+ embeddings:
235
+ name: bge-m3
236
+
237
+ services:
238
+ vectors:
239
+ provider: qdrant
240
+ port: 6333
241
+ cache:
242
+ provider: redis
243
+ max_memory: 256mb
244
+
245
+ gateway:
246
+ port: 8000
247
+ auth: api_key
248
+ rate_limit: 100/min
249
+ cors: ["*"]
250
+
251
+ observe:
252
+ metrics: true
253
+ dashboard_port: 8080
254
+ ```
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
+
282
+ ## Interactive Chat
283
+
284
+ ```bash
285
+ llmstack chat
286
+ ```
287
+
288
+ ```
289
+ LLMStack Chat — model: llama3.2
290
+ Type 'exit' or Ctrl+C to quit. '/clear' to reset conversation.
291
+
292
+ You: What is quantum computing?
293
+ Assistant: Quantum computing uses quantum mechanical phenomena like
294
+ superposition and entanglement to process information...
295
+
296
+ You: /clear
297
+ Conversation cleared.
298
+ ```
299
+
300
+ ## Export to Docker Compose
301
+
302
+ ```bash
303
+ llmstack export
304
+ # Exported 7 services to docker-compose.yml
305
+ # Run with: docker compose up -d
306
+ ```
307
+
308
+ Share the generated file with your team — no llmstack dependency required.
309
+
310
+ ## Use the API
311
+
312
+ ```python
313
+ from openai import OpenAI
314
+
315
+ client = OpenAI(base_url="http://localhost:8000/v1", api_key="YOUR_KEY")
316
+
317
+ # Chat completion
318
+ response = client.chat.completions.create(
319
+ model="llama3.2",
320
+ messages=[{"role": "user", "content": "Explain quantum computing"}]
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"])
347
+ ```
348
+
349
+ ## CLI
350
+
351
+ | Command | Description |
352
+ |---------|-------------|
353
+ | `llmstack init [--preset]` | Create config with smart defaults |
354
+ | `llmstack up [--attach]` | Start all services |
355
+ | `llmstack down [--volumes]` | Stop and clean up |
356
+ | `llmstack status` | Health check all services |
357
+ | `llmstack chat [--model]` | Interactive terminal chat |
358
+ | `llmstack export [--output]` | Generate docker-compose.yml |
359
+ | `llmstack logs <service>` | Stream service logs |
360
+ | `llmstack doctor` | Diagnose system issues |
361
+
362
+ ## Observability
363
+
364
+ When `observe.metrics: true`, llmstack boots Prometheus + Grafana with a pre-built dashboard:
365
+
366
+ - **Request rate** per endpoint
367
+ - **Latency** p50 / p99 histograms
368
+ - **Token throughput** (input + output)
369
+ - **Error rate** (4xx / 5xx)
370
+ - **Cache hit rate**
371
+ - **Circuit breaker state**
372
+ - **Rate limit rejections**
373
+
374
+ Access at `http://localhost:8080` (login: admin / llmstack)
375
+
376
+ ## Comparison
377
+
378
+ | | llmstack | Ollama | LocalAI | AnythingLLM | LiteLLM |
379
+ |---|---|---|---|---|---|
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 |
385
+ | Auto hardware detection | **Yes** | No | No | No | No |
386
+ | OpenAI-compatible API | **Yes** | Yes | Yes | No | Yes |
387
+ | Built-in vector DB | **Yes** | No | No | Bundled | No |
388
+ | Observability dashboard | **Yes** | No | Partial | No | Partial |
389
+ | Plugin ecosystem | **Yes** | No | No | No | No |
390
+
391
+ ## Plugins
392
+
393
+ Extend llmstack with new backends via pip:
394
+
395
+ ```bash
396
+ pip install llmstack-cli-plugin-chromadb
397
+ # Now: vectors.provider: chromadb in llmstack.yaml
398
+ ```
399
+
400
+ Create your own: implement `ServiceBase`, register via entry_points. See [CONTRIBUTING.md](CONTRIBUTING.md).
401
+
402
+ ## Tech stack
403
+
404
+ - **CLI**: [Typer](https://typer.tiangolo.com/) + [Rich](https://rich.readthedocs.io/)
405
+ - **Config**: [Pydantic v2](https://docs.pydantic.dev/)
406
+ - **Gateway**: [FastAPI](https://fastapi.tiangolo.com/) + Redis + Qdrant
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
411
+ - **Metrics**: Prometheus + Grafana
412
+
413
+ ## Requirements
414
+
415
+ - Python 3.11+
416
+ - Docker
417
+
418
+ ## Contributing
419
+
420
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.
421
+
422
+ ## License
423
+
424
+ Apache-2.0