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