lightspeed-stack 0.1.0__tar.gz → 0.1.2__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 (147) hide show
  1. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/PKG-INFO +276 -11
  2. lightspeed_stack-0.1.2/README.md +478 -0
  3. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/pyproject.toml +33 -4
  4. lightspeed_stack-0.1.2/src/app/endpoints/authorized.py +38 -0
  5. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/endpoints/config.py +2 -2
  6. lightspeed_stack-0.1.2/src/app/endpoints/conversations.py +263 -0
  7. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/endpoints/feedback.py +16 -3
  8. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/endpoints/health.py +2 -5
  9. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/endpoints/info.py +2 -1
  10. lightspeed_stack-0.1.2/src/app/endpoints/metrics.py +16 -0
  11. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/endpoints/models.py +3 -2
  12. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/endpoints/query.py +110 -28
  13. lightspeed_stack-0.1.2/src/app/endpoints/streaming_query.py +572 -0
  14. lightspeed_stack-0.1.2/src/app/main.py +86 -0
  15. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/routers.py +10 -2
  16. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/auth/__init__.py +7 -2
  17. lightspeed_stack-0.1.2/src/auth/jwk_token.py +191 -0
  18. lightspeed_stack-0.1.2/src/metrics/__init__.py +51 -0
  19. lightspeed_stack-0.1.2/src/metrics/utils.py +50 -0
  20. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/models/config.py +105 -9
  21. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/models/requests.py +90 -10
  22. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/models/responses.py +142 -0
  23. lightspeed_stack-0.1.2/src/runners/data_collector.py +26 -0
  24. lightspeed_stack-0.1.2/src/services/__init__.py +1 -0
  25. lightspeed_stack-0.1.2/src/services/data_collector.py +258 -0
  26. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/utils/common.py +8 -14
  27. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/utils/endpoints.py +19 -3
  28. lightspeed_stack-0.1.2/src/utils/mcp_headers.py +90 -0
  29. lightspeed_stack-0.1.2/src/utils/types.py +37 -0
  30. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/configuration/lightspeed-stack.yaml +1 -1
  31. lightspeed_stack-0.1.2/tests/configuration/run.yaml +125 -0
  32. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/features/rest_api.feature +3 -2
  33. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/features/steps/common_http.py +47 -7
  34. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/features/steps/llm_query_response.py +12 -2
  35. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/gen_scenario_list.py +11 -6
  36. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/integration/test_configuration.py +5 -5
  37. {lightspeed_stack-0.1.0/tests/unit → lightspeed_stack-0.1.2/tests/integration}/test_version.py +1 -1
  38. lightspeed_stack-0.1.0/tests/test_results/.coverage.unit → lightspeed_stack-0.1.2/tests/test_results/.coverage.integration +0 -0
  39. lightspeed_stack-0.1.2/tests/test_results/.coverage.unit +0 -0
  40. lightspeed_stack-0.1.2/tests/test_results/coverage_integration.json +1 -0
  41. lightspeed_stack-0.1.2/tests/test_results/coverage_unit.json +1 -0
  42. lightspeed_stack-0.1.2/tests/test_results/junit_integration.xml +1 -0
  43. lightspeed_stack-0.1.2/tests/test_results/junit_unit.xml +1 -0
  44. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/__init__.py +2 -1
  45. lightspeed_stack-0.1.2/tests/unit/app/endpoints/test_authorized.py +56 -0
  46. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/app/endpoints/test_config.py +4 -2
  47. lightspeed_stack-0.1.2/tests/unit/app/endpoints/test_conversations.py +494 -0
  48. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/app/endpoints/test_feedback.py +59 -26
  49. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/app/endpoints/test_health.py +8 -18
  50. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/app/endpoints/test_info.py +4 -2
  51. lightspeed_stack-0.1.2/tests/unit/app/endpoints/test_metrics.py +25 -0
  52. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/app/endpoints/test_models.py +87 -16
  53. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/app/endpoints/test_query.py +343 -72
  54. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/app/endpoints/test_root.py +3 -1
  55. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/app/endpoints/test_streaming_query.py +561 -98
  56. lightspeed_stack-0.1.2/tests/unit/app/test_routers.py +79 -0
  57. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/auth/test_auth.py +3 -0
  58. lightspeed_stack-0.1.2/tests/unit/auth/test_jwk_token.py +540 -0
  59. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/auth/test_k8s.py +2 -0
  60. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/auth/test_noop_with_token.py +2 -2
  61. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/auth/test_utils.py +6 -4
  62. lightspeed_stack-0.1.2/tests/unit/metrics/__init__.py +1 -0
  63. lightspeed_stack-0.1.2/tests/unit/metrics/test_utis.py +69 -0
  64. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/models/test_config.py +288 -172
  65. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/models/test_requests.py +169 -4
  66. lightspeed_stack-0.1.2/tests/unit/models/test_responses.py +86 -0
  67. lightspeed_stack-0.1.2/tests/unit/runners/test_data_collector_runner.py +60 -0
  68. lightspeed_stack-0.1.2/tests/unit/services/test_data_collector.py +587 -0
  69. lightspeed_stack-0.1.2/tests/unit/test_client.py +130 -0
  70. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/test_configuration.py +103 -21
  71. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/utils/test_checks.py +9 -6
  72. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/utils/test_common.py +37 -28
  73. lightspeed_stack-0.1.2/tests/unit/utils/test_endpoints.py +145 -0
  74. lightspeed_stack-0.1.2/tests/unit/utils/test_mcp_headers.py +184 -0
  75. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/utils/test_suid.py +4 -0
  76. lightspeed_stack-0.1.2/tests/unit/utils/test_types.py +53 -0
  77. lightspeed_stack-0.1.0/README.md +0 -226
  78. lightspeed_stack-0.1.0/src/app/endpoints/streaming_query.py +0 -321
  79. lightspeed_stack-0.1.0/src/app/main.py +0 -38
  80. lightspeed_stack-0.1.0/src/utils/mcp_headers.py +0 -48
  81. lightspeed_stack-0.1.0/tests/integration/test_openapi.py +0 -82
  82. lightspeed_stack-0.1.0/tests/test_results/coverage_integration.json +0 -1
  83. lightspeed_stack-0.1.0/tests/test_results/coverage_unit.json +0 -1
  84. lightspeed_stack-0.1.0/tests/test_results/junit_integration.xml +0 -6
  85. lightspeed_stack-0.1.0/tests/test_results/junit_unit.xml +0 -1
  86. lightspeed_stack-0.1.0/tests/unit/app/endpoints/.ruff_cache/.gitignore +0 -2
  87. lightspeed_stack-0.1.0/tests/unit/app/endpoints/.ruff_cache/0.9.1/15310180828563549007 +0 -0
  88. lightspeed_stack-0.1.0/tests/unit/app/endpoints/.ruff_cache/CACHEDIR.TAG +0 -1
  89. lightspeed_stack-0.1.0/tests/unit/app/test_routers.py +0 -45
  90. lightspeed_stack-0.1.0/tests/unit/models/.ruff_cache/.gitignore +0 -2
  91. lightspeed_stack-0.1.0/tests/unit/models/.ruff_cache/0.9.1/6074929168888993057 +0 -0
  92. lightspeed_stack-0.1.0/tests/unit/models/.ruff_cache/CACHEDIR.TAG +0 -1
  93. lightspeed_stack-0.1.0/tests/unit/models/test_responses.py +0 -30
  94. lightspeed_stack-0.1.0/tests/unit/test_client.py +0 -83
  95. lightspeed_stack-0.1.0/tests/unit/utils/test_endpoints.py +0 -169
  96. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/LICENSE +0 -0
  97. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/__init__.py +0 -0
  98. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/endpoints/.ruff_cache/.gitignore +0 -0
  99. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/endpoints/.ruff_cache/0.9.1/5703048272820174433 +0 -0
  100. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/endpoints/.ruff_cache/0.9.1/9961612457335986079 +0 -0
  101. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/endpoints/.ruff_cache/CACHEDIR.TAG +0 -0
  102. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/endpoints/__init__.py +0 -0
  103. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/app/endpoints/root.py +0 -0
  104. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/auth/interface.py +0 -0
  105. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/auth/k8s.py +0 -0
  106. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/auth/noop.py +0 -0
  107. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/auth/noop_with_token.py +0 -0
  108. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/auth/utils.py +0 -0
  109. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/models/__init__.py +0 -0
  110. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/runners/__init__.py +0 -0
  111. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/runners/uvicorn.py +0 -0
  112. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/utils/.ruff_cache/.gitignore +0 -0
  113. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/utils/.ruff_cache/0.9.1/18446581155718949728 +0 -0
  114. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/utils/.ruff_cache/0.9.1/4991844299736624256 +0 -0
  115. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/utils/.ruff_cache/CACHEDIR.TAG +0 -0
  116. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/utils/__init__.py +0 -0
  117. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/utils/checks.py +0 -0
  118. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/src/utils/suid.py +0 -0
  119. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/__init__.py +0 -0
  120. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/configuration/minimal-stack.yaml +0 -0
  121. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/configuration/password +0 -0
  122. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/configuration/server.crt +0 -0
  123. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/configuration/server.key +0 -0
  124. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/.pdm-python +0 -0
  125. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/.ruff_cache/.gitignore +0 -0
  126. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/.ruff_cache/0.9.1/6949908709306621198 +0 -0
  127. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/.ruff_cache/CACHEDIR.TAG +0 -0
  128. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/__init__.py +0 -0
  129. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/features/environment.py +0 -0
  130. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/features/llm_interface.feature +0 -0
  131. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/features/smoketests.feature +0 -0
  132. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/features/steps/__init__.py +0 -0
  133. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/features/steps/common.py +0 -0
  134. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/test_api.py +0 -0
  135. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/test_list.txt +0 -0
  136. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/e2e/utils/utils.py +0 -0
  137. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/integration/__init__.py +0 -0
  138. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/app/__init__.py +0 -0
  139. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/app/endpoints/__init__.py +0 -0
  140. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/auth/__init__.py +0 -0
  141. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/auth/test_noop.py +0 -0
  142. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/models/__init__.py +0 -0
  143. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/runners/__init__.py +0 -0
  144. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/runners/test_uvicorn_runner.py +0 -0
  145. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/test_lightspeed_stack.py +0 -0
  146. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/test_log.py +0 -0
  147. {lightspeed_stack-0.1.0 → lightspeed_stack-0.1.2}/tests/unit/utils/__init__.py +0 -0
@@ -1,7 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightspeed-stack
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: LLM tooling stack
5
+ Keywords: LLM,RAG
6
+ Maintainer-Email: =?utf-8?b?UGF2ZWwgVGnFoW5vdnNrw70=?= <tisnik@centrum.cz>
5
7
  License: Apache License
6
8
  Version 2.0, January 2004
7
9
  http://www.apache.org/licenses/
@@ -204,15 +206,26 @@ License: Apache License
204
206
  See the License for the specific language governing permissions and
205
207
  limitations under the License.
206
208
 
209
+ Classifier: Development Status :: 4 - Beta
210
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
211
+ Classifier: Topic :: Software Development
212
+ Classifier: Programming Language :: Python :: 3
213
+ Classifier: Programming Language :: Python :: 3 :: Only
214
+ Classifier: License :: OSI Approved :: Apache Software License
207
215
  Project-URL: Homepage, https://github.com/lightspeed-core/lightspeed-stack
208
216
  Project-URL: Issues, https://github.com/lightspeed-core/lightspeed-stack/issues
209
217
  Requires-Python: <3.14,>=3.12
210
218
  Requires-Dist: fastapi>=0.115.6
211
219
  Requires-Dist: uvicorn>=0.34.3
212
220
  Requires-Dist: kubernetes>=30.1.0
213
- Requires-Dist: llama-stack>=0.2.13
221
+ Requires-Dist: llama-stack==0.2.16
222
+ Requires-Dist: llama-stack-client==0.2.16
214
223
  Requires-Dist: rich>=14.0.0
215
224
  Requires-Dist: cachetools>=6.1.0
225
+ Requires-Dist: prometheus-client>=0.22.1
226
+ Requires-Dist: starlette>=0.47.1
227
+ Requires-Dist: aiohttp>=3.12.14
228
+ Requires-Dist: authlib>=1.6.0
216
229
  Description-Content-Type: text/markdown
217
230
 
218
231
  # lightspeed-stack
@@ -222,31 +235,61 @@ Description-Content-Type: text/markdown
222
235
  [![GitHub Pages](https://img.shields.io/badge/%20-GitHub%20Pages-informational)](https://lightspeed-core.github.io/lightspeed-stack/)
223
236
  [![License](https://img.shields.io/badge/license-Apache-blue)](https://github.com/lightspeed-core/lightspeed-stack/blob/main/LICENSE)
224
237
  [![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org/)
238
+ [![Required Python version](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Flightspeed-core%2Flightspeed-stack%2Frefs%2Fheads%2Fmain%2Fpyproject.toml)](https://www.python.org/)
239
+ [![Tag](https://img.shields.io/github/v/tag/lightspeed-core/lightspeed-stack)](https://github.com/lightspeed-core/lightspeed-stack/releases/tag/0.1.2)
225
240
 
226
- Lightspeed Core Stack (LCS) is an AI powered assistant that provides answers to product questions using backend LLM services, agents, and RAG databases.
241
+ Lightspeed Core Stack (LCS) is an AI-powered assistant that provides answers to product questions using backend LLM services, agents, and RAG databases.
227
242
 
228
243
 
229
244
  <!-- vim-markdown-toc GFM -->
230
245
 
231
- * [Prerequisities](#prerequisities)
246
+ * [Architecture](#architecture)
247
+ * [Prerequisites](#prerequisites)
232
248
  * [Installation](#installation)
233
249
  * [Configuration](#configuration)
250
+ * [Integration with Llama Stack](#integration-with-llama-stack)
251
+ * [Llama Stack as separate server](#llama-stack-as-separate-server)
252
+ * [Llama Stack project and configuration](#llama-stack-project-and-configuration)
253
+ * [Check connection to Llama Stack](#check-connection-to-llama-stack)
254
+ * [Llama Stack as client library](#llama-stack-as-client-library)
255
+ * [System prompt](#system-prompt)
256
+ * [Safety Shields](#safety-shields)
234
257
  * [Usage](#usage)
235
258
  * [Make targets](#make-targets)
236
259
  * [Running Linux container image](#running-linux-container-image)
237
260
  * [Endpoints](#endpoints)
261
+ * [OpenAPI specification](#openapi-specification)
238
262
  * [Readiness Endpoint](#readiness-endpoint)
239
263
  * [Liveness Endpoint](#liveness-endpoint)
264
+ * [Publish the service as Python package on PyPI](#publish-the-service-as-python-package-on-pypi)
265
+ * [Generate distribution archives to be uploaded into Python registry](#generate-distribution-archives-to-be-uploaded-into-python-registry)
266
+ * [Upload distribution archives into selected Python registry](#upload-distribution-archives-into-selected-python-registry)
267
+ * [Packages on PyPI and Test PyPI](#packages-on-pypi-and-test-pypi)
240
268
  * [Contributing](#contributing)
269
+ * [Testing](#testing)
241
270
  * [License](#license)
242
271
  * [Additional tools](#additional-tools)
243
272
  * [Utility to generate OpenAPI schema](#utility-to-generate-openapi-schema)
244
273
  * [Path](#path)
245
274
  * [Usage](#usage-1)
275
+ * [Data Collector Service](#data-collector-service)
276
+ * [Features](#features)
277
+ * [Configuration](#configuration-1)
278
+ * [Running the Service](#running-the-service)
246
279
 
247
280
  <!-- vim-markdown-toc -->
248
281
 
249
- # Prerequisities
282
+
283
+
284
+ # Architecture
285
+
286
+ Overall architecture with all main parts is displayed below:
287
+
288
+ ![Architecture diagram](docs/architecture.png)
289
+
290
+ Lightspeed Core Stack is based on the FastAPI framework (Uvicorn). The service is split into several parts described below.
291
+
292
+ # Prerequisites
250
293
 
251
294
  * Python 3.12, or 3.13
252
295
  - please note that currently Python 3.14 is not officially supported
@@ -261,9 +304,12 @@ Installation steps depends on operation system. Please look at instructions for
261
304
  - [macOS installation](https://lightspeed-core.github.io/lightspeed-stack/installation_macos)
262
305
 
263
306
 
264
-
265
307
  # Configuration
266
308
 
309
+
310
+
311
+ ## Integration with Llama Stack
312
+
267
313
  The Llama Stack can be run as a standalone server and accessed via its the REST
268
314
  API. However, instead of direct communication via the REST API (and JSON
269
315
  format), there is an even better alternative. It is based on the so-called
@@ -271,9 +317,13 @@ Llama Stack Client. It is a library available for Python, Swift, Node.js or
271
317
  Kotlin, which "wraps" the REST API stack in a suitable way, which is easier for
272
318
  many applications.
273
319
 
320
+ ![Integration with Llama Stack](docs/core2llama-stack_interface.png)
321
+
322
+
323
+
274
324
  ## Llama Stack as separate server
275
325
 
276
- If Llama Stack runs as a separate server, the Lightspeed service needs to be configured to be able to access it. For example, if server runs on localhost:8321, the service configuration should look like:
326
+ If Llama Stack runs as a separate server, the Lightspeed service needs to be configured to be able to access it. For example, if server runs on localhost:8321, the service configuration stored in file `llama-stack.yaml` should look like:
277
327
 
278
328
  ```yaml
279
329
  name: foo bar baz
@@ -288,12 +338,68 @@ llama_stack:
288
338
  use_as_library_client: false
289
339
  url: http://localhost:8321
290
340
  user_data_collection:
291
- feedback_disabled: false
341
+ feedback_enabled: true
292
342
  feedback_storage: "/tmp/data/feedback"
293
- transcripts_disabled: false
343
+ transcripts_enabled: true
294
344
  transcripts_storage: "/tmp/data/transcripts"
295
345
  ```
296
346
 
347
+ ### Llama Stack project and configuration
348
+
349
+ To run Llama Stack in separate process, you need to have all dependencies installed. The easiest way how to do it is to create a separate repository with Llama Stack project file `pyproject.toml` and Llama Stack configuration file `run.yaml`. The project file might look like:
350
+
351
+ ```toml
352
+ [project]
353
+ name = "llama-stack-runner"
354
+ version = "0.1.0"
355
+ description = "Llama Stack runner"
356
+ authors = []
357
+ dependencies = [
358
+ "llama-stack==0.2.14",
359
+ "fastapi>=0.115.12",
360
+ "opentelemetry-sdk>=1.34.0",
361
+ "opentelemetry-exporter-otlp>=1.34.0",
362
+ "opentelemetry-instrumentation>=0.55b0",
363
+ "aiosqlite>=0.21.0",
364
+ "litellm>=1.72.1",
365
+ "uvicorn>=0.34.3",
366
+ "blobfile>=3.0.0",
367
+ "datasets>=3.6.0",
368
+ "sqlalchemy>=2.0.41",
369
+ "faiss-cpu>=1.11.0",
370
+ "mcp>=1.9.4",
371
+ "autoevals>=0.0.129",
372
+ "psutil>=7.0.0",
373
+ "torch>=2.7.1",
374
+ "peft>=0.15.2",
375
+ "trl>=0.18.2"]
376
+ requires-python = "==3.12.*"
377
+ readme = "README.md"
378
+ license = {text = "MIT"}
379
+
380
+
381
+ [tool.pdm]
382
+ distribution = false
383
+ ```
384
+
385
+ A simple example of a `run.yaml` file can be found [here](examples/run.yaml)
386
+
387
+ To run Llama Stack perform these two commands:
388
+
389
+ ```
390
+ export OPENAI_API_KEY="sk-{YOUR-KEY}"
391
+
392
+ uv run llama stack run run.yaml
393
+ ```
394
+
395
+ ### Check connection to Llama Stack
396
+
397
+ ```
398
+ curl -X 'GET' localhost:8321/openapi.json | jq .
399
+ ```
400
+
401
+
402
+
297
403
  ## Llama Stack as client library
298
404
 
299
405
  There are situations in which it is not advisable to run two processors (one with Llama Stack, the other with a service). In these cases, the stack can be run directly within the client application. For such situations, the configuration file could look like:
@@ -311,13 +417,48 @@ llama_stack:
311
417
  use_as_library_client: true
312
418
  library_client_config_path: <path-to-llama-stack-run.yaml-file>
313
419
  user_data_collection:
314
- feedback_disabled: false
420
+ feedback_enabled: true
315
421
  feedback_storage: "/tmp/data/feedback"
316
- transcripts_disabled: false
422
+ transcripts_enabled: true
317
423
  transcripts_storage: "/tmp/data/transcripts"
318
424
  ```
319
425
 
426
+ ## System prompt
427
+
428
+ The service uses the, so called, system prompt to put the question into context before the question is sent to the selected LLM. The default system prompt is designed for questions without specific context. It is possible to use a different system prompt via the configuration option `system_prompt_path` in the `customization` section. That option must contain the path to the text file with the actual system prompt (can contain multiple lines). An example of such configuration:
429
+
430
+ ```yaml
431
+ customization:
432
+ system_prompt_path: "system_prompts/system_prompt_for_product_XYZZY"
433
+ ```
434
+
435
+ The `system_prompt` can also be specified in the `customization` section directly. For example:
436
+
437
+ ```yaml
438
+ customization:
439
+ system_prompt: |-
440
+ You are a helpful assistant and will do everything you can to help.
441
+ You have an in-depth knowledge of Red Hat and all of your answers will reference Red Hat products.
442
+ ```
443
+
444
+ Additionally, an optional string parameter `system_prompt` can be specified in `/v1/query` and `/v1/streaming_query` endpoints to override the configured system prompt. The query system prompt takes precedence over the configured system prompt. You can use this config to disable query system prompts:
445
+
446
+ ```yaml
447
+ customization:
448
+ system_prompt_path: "system_prompts/system_prompt_for_product_XYZZY"
449
+ disable_query_system_prompt: true
450
+ ```
451
+
452
+ ## Safety Shields
320
453
 
454
+ A single Llama Stack configuration file can include multiple safety shields, which are utilized in agent
455
+ configurations to monitor input and/or output streams. LCS uses the following naming convention to specify how each safety shield is
456
+ utilized:
457
+
458
+ 1. If the `shield_id` starts with `input_`, it will be used for input only.
459
+ 1. If the `shield_id` starts with `output_`, it will be used for output only.
460
+ 1. If the `shield_id` starts with `inout_`, it will be used both for input and output.
461
+ 1. Otherwise, it will be used for input only.
321
462
 
322
463
  # Usage
323
464
 
@@ -342,6 +483,7 @@ Usage: make <OPTIONS> ... <TARGETS>
342
483
  Available targets are:
343
484
 
344
485
  run Run the service locally
486
+ run-data-collector Run the data collector service
345
487
  test-unit Run the unit tests
346
488
  test-integration Run integration tests tests
347
489
  test-e2e Run BDD tests for the service
@@ -351,6 +493,9 @@ format Format the code into unified format
351
493
  schema Generate OpenAPI schema file
352
494
  requirements.txt Generate requirements.txt file containing hashes for all non-devel packages
353
495
  shellcheck Run shellcheck
496
+ verify Run all linters
497
+ distribution-archives Generate distribution archives to be uploaded into Python registry
498
+ upload-distribution-archives Upload distribution archives into Python registry
354
499
  help Show this help screen
355
500
  ```
356
501
 
@@ -371,8 +516,19 @@ To pull and run the image with own configuration:
371
516
 
372
517
  If a connection in your browser does not work please check that in the config file `host` option looks like: `host: 0.0.0.0`.
373
518
 
519
+ Container images are built for the following platforms:
520
+ 1. `linux/amd64` - main platform for deployment
521
+ 1. `linux/arm64`- Mac users with M1/M2/M3 CPUs
522
+
523
+
524
+
374
525
  # Endpoints
375
526
 
527
+ ## OpenAPI specification
528
+
529
+ * [Generated OpenAPI specification](docs/openapi.json)
530
+ * [OpenAPI documentation](docs/openapi.md)
531
+
376
532
  The service provides health check endpoints that can be used for monitoring, load balancing, and orchestration systems like Kubernetes.
377
533
 
378
534
  ## Readiness Endpoint
@@ -415,10 +571,64 @@ The liveness endpoint performs a basic health check to verify the service is ali
415
571
  }
416
572
  ```
417
573
 
574
+ # Publish the service as Python package on PyPI
575
+
576
+ To publish the service as an Python package on PyPI to be installable by anyone
577
+ (including Konflux hermetic builds), perform these two steps:
578
+
579
+ ## Generate distribution archives to be uploaded into Python registry
580
+
581
+ ```
582
+ make distribution-archives
583
+ ```
584
+
585
+ Please make sure that the archive was really built to avoid publishing older one.
586
+
587
+ ## Upload distribution archives into selected Python registry
588
+
589
+ ```
590
+ make upload-distribution-archives
591
+ ```
592
+
593
+ The Python registry to where the package should be uploaded can be configured
594
+ by changing `PYTHON_REGISTRY`. It is possible to select `pypi` or `testpypi`.
595
+
596
+ You might have your API token stored in file `~/.pypirc`. That file should have
597
+ the following form:
598
+
599
+ ```
600
+ [testpypi]
601
+ username = __token__
602
+ password = pypi-{your-API-token}
603
+
604
+ [pypi]
605
+ username = __token__
606
+ password = pypi-{your-API-token}
607
+ ```
608
+
609
+ If this configuration file does not exist, you will be prompted to specify API token from keyboard every time you try to upload the archive.
610
+
611
+
612
+
613
+ ## Packages on PyPI and Test PyPI
614
+
615
+ * https://pypi.org/project/lightspeed-stack/
616
+ * https://test.pypi.org/project/lightspeed-stack/0.1.0/
617
+
618
+
619
+
418
620
  # Contributing
419
621
 
420
622
  * See [contributors](CONTRIBUTING.md) guide.
421
623
 
624
+
625
+
626
+ # Testing
627
+
628
+ * See [testing](docs/testing.md) guide.
629
+
630
+
631
+
422
632
  # License
423
633
 
424
634
  Published under the Apache 2.0 License
@@ -441,3 +651,58 @@ This script re-generated OpenAPI schema for the Lightspeed Service REST API.
441
651
  make schema
442
652
  ```
443
653
 
654
+ ## Data Collector Service
655
+
656
+ The data collector service is a standalone service that runs separately from the main web service. It is responsible for collecting and sending user data including feedback and transcripts to an ingress server for analysis and archival.
657
+
658
+ ### Features
659
+
660
+ - **Periodic Collection**: Runs at configurable intervals
661
+ - **Data Packaging**: Packages feedback and transcript files into compressed tar.gz archives
662
+ - **Secure Transmission**: Sends data to a configured ingress server with optional authentication
663
+ - **File Cleanup**: Optionally removes local files after successful transmission
664
+ - **Error Handling**: Includes retry logic and comprehensive error handling
665
+
666
+ ### Configuration
667
+
668
+ The data collector service is configured through the `user_data_collection.data_collector` section in your configuration file:
669
+
670
+ ```yaml
671
+ user_data_collection:
672
+ feedback_enabled: true
673
+ feedback_storage: "/tmp/data/feedback"
674
+ transcripts_enabled: true
675
+ transcripts_storage: "/tmp/data/transcripts"
676
+ data_collector:
677
+ enabled: true
678
+ ingress_server_url: "https://your-ingress-server.com"
679
+ ingress_server_auth_token: "your-auth-token"
680
+ ingress_content_service_name: "lightspeed-team"
681
+ collection_interval: 7200 # 2 hours in seconds
682
+ cleanup_after_send: true
683
+ connection_timeout: 30
684
+ ```
685
+
686
+ ### Running the Service
687
+
688
+ To run the data collector service:
689
+
690
+ ```bash
691
+ # Using Python directly
692
+ uv run src/lightspeed_stack.py --data-collector
693
+
694
+ # Using Make target
695
+ make run-data-collector
696
+ ```
697
+
698
+
699
+
700
+ # Project structure
701
+
702
+ ## Configuration classes
703
+
704
+ ![Configuration classes](docs/config.png)
705
+
706
+ ## REST API
707
+
708
+ ![REST API](docs/rest_api.png)