Skip to content

Commit 0d774ce

Browse files
committed
rebase and resolve conflict
Signed-off-by: Anxhela Coba <[email protected]>
2 parents 0dd1f1d + 73208b2 commit 0d774ce

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3440
-942
lines changed

.github/workflows/e2e_tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ jobs:
6565
isAbsolutePath: false
6666
file: 'lightspeed-stack.yaml'
6767
content: |
68-
name: foo bar baz
68+
name: Lightspeed Core Service (LCS)
6969
service:
7070
host: 0.0.0.0
7171
port: 8080

CLAUDE.md

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# Lightspeed Core Stack Development Guide
2+
3+
## Project Overview
4+
Lightspeed Core Stack (LCS) is an AI-powered assistant built on FastAPI that provides answers using LLM services, agents, and RAG databases. It integrates with Llama Stack for AI operations.
5+
6+
## Development Environment
7+
- **Python**: Check `pyproject.toml` for supported Python versions
8+
- **Package Manager**: uv (use `uv run` for all commands)
9+
- **Required Commands**:
10+
- `uv run make format` - Format code (black + ruff)
11+
- `uv run make verify` - Run all linters (black, pylint, pyright, ruff, docstyle, check-types)
12+
13+
## Code Architecture & Patterns
14+
15+
### Project Structure
16+
```
17+
src/
18+
├── app/ # FastAPI application
19+
│ ├── endpoints/ # REST API endpoints
20+
│ └── main.py # Application entry point
21+
├── auth/ # Authentication modules (k8s, jwk, noop)
22+
├── authorization/ # Authorization middleware & resolvers
23+
├── models/ # Pydantic models
24+
│ ├── config.py # Configuration classes
25+
│ ├── requests.py # Request models
26+
│ └── responses.py # Response models
27+
├── utils/ # Utility functions
28+
├── client.py # Llama Stack client wrapper
29+
└── configuration.py # Config management
30+
```
31+
32+
### Coding Standards
33+
34+
#### Imports & Dependencies
35+
- Use absolute imports for internal modules: `from auth import get_auth_dependency`
36+
- FastAPI dependencies: `from fastapi import APIRouter, HTTPException, Request, status, Depends`
37+
- Llama Stack imports: `from llama_stack_client import AsyncLlamaStackClient`
38+
- **ALWAYS** check `pyproject.toml` for existing dependencies before adding new ones
39+
- **ALWAYS** verify current library versions in `pyproject.toml` rather than assuming versions
40+
41+
#### Module Standards
42+
- All modules start with descriptive docstrings explaining purpose
43+
- Use `logger = logging.getLogger(__name__)` pattern for module logging
44+
- Package `__init__.py` files contain brief package descriptions
45+
- Central `constants.py` for shared constants with descriptive comments
46+
- Type aliases defined at module level for clarity
47+
48+
#### Configuration
49+
- All config uses Pydantic models extending `ConfigurationBase`
50+
- Base class sets `extra="forbid"` to reject unknown fields
51+
- Use `@field_validator` and `@model_validator` for custom validation
52+
- Type hints: `Optional[FilePath]`, `PositiveInt`, `SecretStr`
53+
54+
#### Function Standards
55+
- **Documentation**: All functions require docstrings with brief descriptions
56+
- **Type Annotations**: Complete type annotations for parameters and return types
57+
- Use `typing_extensions.Self` for model validators
58+
- Union types: `str | int` (modern syntax)
59+
- Optional: `Optional[Type]` or `Type | None`
60+
- **Naming**: Use snake_case with descriptive, action-oriented names (get_, validate_, check_)
61+
- **Return Values**: **CRITICAL** - Avoid in-place parameter modification anti-patterns:
62+
```python
63+
# ❌ BAD: Modifying parameter in-place
64+
def process_data(input_data: Any, result_dict: dict) -> None:
65+
result_dict[key] = value # Anti-pattern
66+
67+
# ✅ GOOD: Return new data structure
68+
def process_data(input_data: Any) -> dict:
69+
result_dict = {}
70+
result_dict[key] = value
71+
return result_dict
72+
```
73+
- **Async Functions**: Use `async def` for I/O operations and external API calls
74+
- **Error Handling**:
75+
- Use FastAPI `HTTPException` with appropriate status codes for API endpoints
76+
- Handle `APIConnectionError` from Llama Stack
77+
78+
#### Logging Standards
79+
- Use `import logging` and module logger pattern: `logger = logging.getLogger(__name__)`
80+
- Standard log levels with clear purposes:
81+
- `logger.debug()` - Detailed diagnostic information
82+
- `logger.info()` - General information about program execution
83+
- `logger.warning()` - Something unexpected happened or potential problems
84+
- `logger.error()` - Serious problems that prevented function execution
85+
86+
#### Class Standards
87+
- **Documentation**: All classes require descriptive docstrings explaining purpose
88+
- **Naming**: Use PascalCase with descriptive names and standard suffixes:
89+
- `Configuration` for config classes
90+
- `Error`/`Exception` for custom exceptions
91+
- `Resolver` for strategy pattern implementations
92+
- `Interface` for abstract base classes
93+
- **Pydantic Models**: Extend `ConfigurationBase` for config, `BaseModel` for data models
94+
- **Abstract Classes**: Use ABC for interfaces with `@abstractmethod` decorators
95+
- **Validation**: Use `@model_validator` and `@field_validator` for Pydantic models
96+
- **Type Hints**: Complete type annotations for all class attributes
97+
98+
#### Docstring Standards
99+
- Follow Google Python docstring conventions: https://google.github.io/styleguide/pyguide.html
100+
- Required for all modules, classes, and functions
101+
- Include brief description and detailed sections as needed:
102+
- `Args:` for function parameters
103+
- `Returns:` for return values
104+
- `Raises:` for exceptions that may be raised
105+
- `Attributes:` for class attributes (Pydantic models)
106+
107+
108+
## Testing Framework
109+
110+
### Test Structure
111+
```
112+
tests/
113+
├── unit/ # Unit tests (pytest)
114+
├── integration/ # Integration tests
115+
└── e2e/ # End-to-end tests (behave)
116+
└── features/ # Gherkin feature files
117+
```
118+
119+
### Testing Framework Requirements
120+
- **Required**: Use pytest for all unit and integration tests
121+
- **Forbidden**: Do not use unittest - pytest is the standard for this project
122+
- **E2E Tests**: Use behave (BDD) framework for end-to-end testing
123+
124+
### Unit Tests (pytest)
125+
- **Fixtures**: Use `conftest.py` for shared fixtures
126+
- **Mocking**: `pytest-mock` for AsyncMock objects
127+
- **Common Pattern**:
128+
```python
129+
@pytest.fixture(name="prepare_agent_mocks")
130+
def prepare_agent_mocks_fixture(mocker):
131+
mock_client = mocker.AsyncMock()
132+
mock_agent = mocker.AsyncMock()
133+
mock_agent._agent_id = "test_agent_id"
134+
return mock_client, mock_agent
135+
```
136+
- **Auth Mock**: `MOCK_AUTH = ("mock_user_id", "mock_username", False, "mock_token")`
137+
- **Coverage**: Unit tests require 60% coverage, integration 10%
138+
139+
### E2E Tests (behave)
140+
- **Framework**: Behave (BDD) with Gherkin feature files
141+
- **Step Definitions**: In `tests/e2e/features/steps/`
142+
- **Common Steps**: Service status, authentication, HTTP requests
143+
- **Test List**: Maintained in `tests/e2e/test_list.txt`
144+
145+
### Test Commands
146+
```bash
147+
uv run make test-unit # Unit tests with coverage
148+
uv run make test-integration # Integration tests
149+
uv run make test-e2e # End-to-end tests
150+
```
151+
152+
## Quality Assurance
153+
154+
### Required Before Completion
155+
1. `uv run make format` - Auto-format code
156+
2. `uv run make verify` - Run all linters
157+
3. Create unit tests for new code
158+
4. Ensure tests pass
159+
160+
### Linting Tools
161+
- **black**: Code formatting
162+
- **pylint**: Static analysis (`source-roots = "src"`)
163+
- **pyright**: Type checking (excludes `src/auth/k8s.py`)
164+
- **ruff**: Fast linter
165+
- **pydocstyle**: Docstring style
166+
- **mypy**: Additional type checking
167+
168+
### Security
169+
- **bandit**: Security issue detection
170+
- Never commit secrets/keys
171+
- Use environment variables for sensitive data
172+
173+
## Key Dependencies
174+
**IMPORTANT**: Always check `pyproject.toml` for current versions rather than relying on this list:
175+
- **FastAPI**: Web framework
176+
- **Llama Stack**: AI integration
177+
- **Pydantic**: Data validation/serialization
178+
- **SQLAlchemy**: Database ORM
179+
- **Kubernetes**: K8s auth integration
180+
181+
## Development Workflow
182+
1. Use `uv sync --group dev --group llslibdev` for dependencies
183+
2. Always use `uv run` prefix for commands
184+
3. **ALWAYS** check `pyproject.toml` for existing dependencies and versions before adding new ones
185+
4. Follow existing code patterns in the module you're modifying
186+
5. Write unit tests covering new functionality
187+
6. Run format and verify before completion

README.md

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ The service includes comprehensive user data collection capabilities for various
5151
* [Llama-Stack as Separate Service (Server Mode)](#llama-stack-as-separate-service-server-mode)
5252
* [Llama-Stack as Library (Library Mode)](#llama-stack-as-library-library-mode)
5353
* [Verify it's running properly](#verify-its-running-properly)
54+
* [Custom Container Image](#custom-container-image)
5455
* [Endpoints](#endpoints)
5556
* [OpenAPI specification](#openapi-specification)
5657
* [Readiness Endpoint](#readiness-endpoint)
@@ -244,7 +245,7 @@ version = "0.1.0"
244245
description = "Llama Stack runner"
245246
authors = []
246247
dependencies = [
247-
"llama-stack==0.2.19",
248+
"llama-stack==0.2.20",
248249
"fastapi>=0.115.12",
249250
"opentelemetry-sdk>=1.34.0",
250251
"opentelemetry-exporter-otlp>=1.34.0",
@@ -693,6 +694,82 @@ A simple sanity check:
693694
curl -H "Accept: application/json" http://localhost:8080/v1/models
694695
```
695696

697+
## Custom Container Image
698+
699+
The lightspeed-stack container image bundles many Python dependencies for common
700+
Llama-Stack providers (when using Llama-Stack in library mode).
701+
702+
Follow these instructons when you need to bundle additional configuration
703+
files or extra dependencies (e.g. `lightspeed-stack-providers`).
704+
705+
To include more dependencies in the base-image, create upstream pull request to update
706+
[the pyproject.toml file](https://github.com/lightspeed-core/lightspeed-stack/blob/main/pyproject.toml)
707+
708+
1. Create `pyproject.toml` file in your top-level directory with content like:
709+
```toml
710+
[project]
711+
name = "my-customized-chatbot"
712+
version = "0.1.0"
713+
description = "My very Awesome Chatbot"
714+
readme = "README.md"
715+
requires-python = ">=3.12"
716+
dependencies = [
717+
"lightspeed-stack-providers==TODO",
718+
]
719+
```
720+
721+
2. Create `Containerfile` in top-level directory like following. Update it as needed:
722+
```
723+
# Latest dev image built from the git main branch (consider pinning a digest for reproducibility)
724+
FROM quay.io/lightspeed-core/lightspeed-stack:dev-latest
725+
726+
ARG APP_ROOT=/app-root
727+
WORKDIR /app-root
728+
729+
# Add additional files
730+
# (avoid accidental inclusion of local directories or env files or credentials)
731+
COPY pyproject.toml LICENSE.md README.md ./
732+
733+
# Bundle own configuration files
734+
COPY lightspeed-stack.yaml run.yaml ./
735+
736+
# Add only project-specific dependencies without adding other dependencies
737+
# to not break the dependencies of the base image.
738+
ENV UV_COMPILE_BYTECODE=0 \
739+
UV_LINK_MODE=copy \
740+
UV_PYTHON_DOWNLOADS=0 \
741+
UV_NO_CACHE=1
742+
# List of dependencies is first parsed from pyproject.toml and then installed.
743+
RUN python -c "import tomllib, sys; print(' '.join(tomllib.load(open('pyproject.toml','rb'))['project']['dependencies']))" \
744+
| xargs uv pip install --no-deps
745+
# Install the project itself
746+
RUN uv pip install . --no-deps && uv clean
747+
748+
USER 0
749+
750+
# Bundle additional rpm packages
751+
RUN microdnf install -y --nodocs --setopt=keepcache=0 --setopt=tsflags=nodocs TODO1 TODO2 \
752+
&& microdnf clean all \
753+
&& rm -rf /var/cache/dnf
754+
755+
# this directory is checked by ecosystem-cert-preflight-checks task in Konflux
756+
COPY LICENSE.md /licenses/
757+
758+
# Add executables from .venv to system PATH
759+
ENV PATH="/app-root/.venv/bin:$PATH"
760+
761+
# Run the application
762+
EXPOSE 8080
763+
ENTRYPOINT ["python3.12", "src/lightspeed_stack.py"]
764+
USER 1001
765+
```
766+
767+
3. Optionally create customized configuration files `lightspeed-stack.yaml` and `run.yaml`.
768+
769+
4. Now try to build your image
770+
```
771+
podman build -t "my-awesome-chatbot:latest" .
772+
```
696773

697774
# Endpoints
698775

docs/architecture.png

2.57 KB
Loading

docs/architecture.svg

Lines changed: 7 additions & 6 deletions
Loading

docs/config.png

1.94 KB
Loading

docs/config.puml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class "CORSConfiguration" as src.models.config.CORSConfiguration {
2929
class "Configuration" as src.models.config.Configuration {
3030
authentication : Optional[AuthenticationConfiguration]
3131
authorization : Optional[AuthorizationConfiguration]
32+
conversation_cache : Optional[ConversationCacheConfiguration]
3233
customization : Optional[Customization]
3334
database : Optional[DatabaseConfiguration]
3435
inference : Optional[InferenceConfiguration]
@@ -42,8 +43,22 @@ class "Configuration" as src.models.config.Configuration {
4243
class "ConfigurationBase" as src.models.config.ConfigurationBase {
4344
model_config
4445
}
46+
class "ConversationCacheConfiguration" as src.models.config.ConversationCacheConfiguration {
47+
memory : Optional[InMemoryCacheConfig]
48+
postgres : Optional[PostgreSQLDatabaseConfiguration]
49+
sqlite : Optional[SQLiteDatabaseConfiguration]
50+
type : Literal['memory', 'sqlite', 'postgres'] | None
51+
check_cache_configuration() -> Self
52+
}
53+
class "CustomProfile" as src.models.config.CustomProfile {
54+
path : str
55+
prompts : Optional[dict[str, str]]
56+
get_prompts() -> dict[str, str]
57+
}
4558
class "Customization" as src.models.config.Customization {
59+
custom_profile : Optional[CustomProfile]
4660
disable_query_system_prompt : bool
61+
profile_path : Optional[str]
4762
system_prompt : Optional[str]
4863
system_prompt_path : Optional[FilePath]
4964
check_customization_model() -> Self
@@ -55,6 +70,9 @@ class "DatabaseConfiguration" as src.models.config.DatabaseConfiguration {
5570
sqlite : Optional[SQLiteDatabaseConfiguration]
5671
check_database_configuration() -> Self
5772
}
73+
class "InMemoryCacheConfig" as src.models.config.InMemoryCacheConfig {
74+
max_entries : Annotated
75+
}
5876
class "InferenceConfiguration" as src.models.config.InferenceConfiguration {
5977
default_model : Optional[str]
6078
default_provider : Optional[str]
@@ -139,8 +157,10 @@ src.models.config.AuthenticationConfiguration --|> src.models.config.Configurati
139157
src.models.config.AuthorizationConfiguration --|> src.models.config.ConfigurationBase
140158
src.models.config.CORSConfiguration --|> src.models.config.ConfigurationBase
141159
src.models.config.Configuration --|> src.models.config.ConfigurationBase
160+
src.models.config.ConversationCacheConfiguration --|> src.models.config.ConfigurationBase
142161
src.models.config.Customization --|> src.models.config.ConfigurationBase
143162
src.models.config.DatabaseConfiguration --|> src.models.config.ConfigurationBase
163+
src.models.config.InMemoryCacheConfig --|> src.models.config.ConfigurationBase
144164
src.models.config.InferenceConfiguration --|> src.models.config.ConfigurationBase
145165
src.models.config.JwkConfiguration --|> src.models.config.ConfigurationBase
146166
src.models.config.JwtConfiguration --|> src.models.config.ConfigurationBase
@@ -152,6 +172,7 @@ src.models.config.SQLiteDatabaseConfiguration --|> src.models.config.Configurati
152172
src.models.config.ServiceConfiguration --|> src.models.config.ConfigurationBase
153173
src.models.config.TLSConfiguration --|> src.models.config.ConfigurationBase
154174
src.models.config.UserDataCollection --|> src.models.config.ConfigurationBase
175+
src.models.config.CustomProfile --* src.models.config.Customization : custom_profile
155176
src.models.config.JsonPathOperator --* src.models.config.JwtRoleRule : operator
156177
src.models.config.LlamaStackConfiguration --* src.models.config.Configuration : llama_stack
157178
src.models.config.SQLiteDatabaseConfiguration --* src.models.config.DatabaseConfiguration : sqlite

0 commit comments

Comments
 (0)