Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/devel_doc/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -18084,13 +18084,13 @@
},
"type": "array",
"title": "Tool RAG IDs",
"description": "RAG IDs made available to the LLM as a file_search tool. Use 'okp' to include the OKP vector store. When omitted, all registered BYOK vector stores are used (backward compatibility)."
"description": "RAG IDs made available to the LLM as a file_search tool. Use 'okp' to include the OKP vector store. When omitted, tool RAG is disabled."
}
},
"additionalProperties": false,
"type": "object",
"title": "RagConfiguration",
"description": "RAG strategy configuration.\n\nControls which RAG sources are used for inline and tool-based retrieval.\n\nEach strategy lists RAG IDs to include. The special ID ``\"okp\"`` defined in constants,\nactivates the OKP provider; all other IDs refer to entries in ``byok_rag``.\n\nBackward compatibility:\n - ``inline`` defaults to ``[]`` (no inline RAG).\n - ``tool`` defaults to ``[]`` (no tool RAG).\n\nIf no RAG strategy is defined (inline and tool are empty),\nthe RAG tool will register all stores available to llama-stack."
"description": "RAG strategy configuration.\n\nControls which RAG sources are used for inline and tool-based retrieval.\n\nEach strategy lists RAG IDs to include. The special ID ``\"okp\"`` defined in constants,\nactivates the OKP provider; all other IDs refer to entries in ``byok_rag``.\n\nBoth ``inline`` and ``tool`` default to ``[]`` (disabled).\nEach must be explicitly configured to activate its respective RAG strategy."
},
"ReadinessResponse": {
"properties": {
Expand Down
10 changes: 3 additions & 7 deletions docs/devel_doc/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -8155,18 +8155,14 @@ Controls which RAG sources are used for inline and tool-based retrieval.
Each strategy lists RAG IDs to include. The special ID ``"okp"`` defined in constants,
activates the OKP provider; all other IDs refer to entries in ``byok_rag``.

Backward compatibility:
- ``inline`` defaults to ``[]`` (no inline RAG).
- ``tool`` defaults to ``[]`` (no tool RAG).

If no RAG strategy is defined (inline and tool are empty),
the RAG tool will register all stores available to llama-stack.
Both ``inline`` and ``tool`` default to ``[]`` (disabled).
Each must be explicitly configured to activate its respective RAG strategy.


| Field | Type | Description |
|-------|------|-------------|
| inline | array | RAG IDs whose sources are injected as context before the LLM call. Use 'okp' to enable OKP inline RAG. Empty by default (no inline RAG). |
| tool | array | RAG IDs made available to the LLM as a file_search tool. Use 'okp' to include the OKP vector store. When omitted, all registered BYOK vector stores are used (backward compatibility). |
| tool | array | RAG IDs made available to the LLM as a file_search tool. Use 'okp' to include the OKP vector store. When omitted, tool RAG is disabled. |


## ReadinessResponse
Expand Down
10 changes: 3 additions & 7 deletions docs/models/responses_succ.md
Original file line number Diff line number Diff line change
Expand Up @@ -1840,18 +1840,14 @@ Controls which RAG sources are used for inline and tool-based retrieval.
Each strategy lists RAG IDs to include. The special ID ``"okp"`` defined in constants,
activates the OKP provider; all other IDs refer to entries in ``byok_rag``.

Backward compatibility:
- ``inline`` defaults to ``[]`` (no inline RAG).
- ``tool`` defaults to ``[]`` (no tool RAG).

If no RAG strategy is defined (inline and tool are empty),
the RAG tool will register all stores available to llama-stack.
Both ``inline`` and ``tool`` default to ``[]`` (disabled).
Each must be explicitly configured to activate its respective RAG strategy.


| Field | Type | Description |
|-------|------|-------------|
| inline | array | RAG IDs whose sources are injected as context before the LLM call. Use 'okp' to enable OKP inline RAG. Empty by default (no inline RAG). |
| tool | array | RAG IDs made available to the LLM as a file_search tool. Use 'okp' to include the OKP vector store. When omitted, all registered BYOK vector stores are used (backward compatibility). |
| tool | array | RAG IDs made available to the LLM as a file_search tool. Use 'okp' to include the OKP vector store. When omitted, tool RAG is disabled. |


## ReadinessResponse
Expand Down
2 changes: 1 addition & 1 deletion docs/user_doc/byok_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ rag:
- okp # include OKP context inline

# Tool RAG: the LLM can call file_search to retrieve context on demand
# If omitted, tool RAG is disabled. If both tool and inline are omitted, all registered stores are used as fallback
# If omitted, tool RAG is disabled
tool:
- my-docs # expose this BYOK store as the file_search tool
- okp # expose OKP as the file_search tool
Expand Down
10 changes: 3 additions & 7 deletions docs/user_doc/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -606,18 +606,14 @@ Controls which RAG sources are used for inline and tool-based retrieval.
Each strategy lists RAG IDs to include. The special ID ``"okp"`` defined in constants,
activates the OKP provider; all other IDs refer to entries in ``byok_rag``.

Backward compatibility:
- ``inline`` defaults to ``[]`` (no inline RAG).
- ``tool`` defaults to ``[]`` (no tool RAG).

If no RAG strategy is defined (inline and tool are empty),
the RAG tool will register all stores available to llama-stack.
Both ``inline`` and ``tool`` default to ``[]`` (disabled).
Each must be explicitly configured to activate its respective RAG strategy.


| Field | Type | Description |
|--------|-------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| inline | array | RAG IDs whose sources are injected as context before the LLM call. Use 'okp' to enable OKP inline RAG. Empty by default (no inline RAG). |
| tool | array | RAG IDs made available to the LLM as a file_search tool. Use 'okp' to include the OKP vector store. When omitted, all registered BYOK vector stores are used (backward compatibility). |
| tool | array | RAG IDs made available to the LLM as a file_search tool. Use 'okp' to include the OKP vector store. When omitted, tool RAG is disabled. |


## RerankerConfiguration
Expand Down
2 changes: 1 addition & 1 deletion examples/lightspeed-stack-byok-okp-rag.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ rag:
- okp
# Tool RAG: LLM can call file_search on demand to retrieve context
# List rag_ids from byok_rag, or 'okp' to include OKP
# Omit to use all registered BYOK stores (backward compatibility)
# Omit to disable tool RAG
tool:
- ocp-docs
- knowledge-base
Expand Down
10 changes: 3 additions & 7 deletions src/models/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2258,12 +2258,8 @@ class RagConfiguration(ConfigurationBase):
Each strategy lists RAG IDs to include. The special ID ``"okp"`` defined in constants,
activates the OKP provider; all other IDs refer to entries in ``byok_rag``.

Backward compatibility:
- ``inline`` defaults to ``[]`` (no inline RAG).
- ``tool`` defaults to ``[]`` (no tool RAG).

If no RAG strategy is defined (inline and tool are empty),
the RAG tool will register all stores available to llama-stack.
Both ``inline`` and ``tool`` default to ``[]`` (disabled).
Each must be explicitly configured to activate its respective RAG strategy.
"""

inline: list[str] = Field(
Expand All @@ -2278,7 +2274,7 @@ class RagConfiguration(ConfigurationBase):
title="Tool RAG IDs",
description="RAG IDs made available to the LLM as a file_search tool. "
f"Use '{constants.OKP_RAG_ID}' to include the OKP vector store. "
"When omitted, all registered BYOK vector stores are used (backward compatibility).",
"When omitted, tool RAG is disabled.",
)


Expand Down
29 changes: 2 additions & 27 deletions src/utils/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@
from llama_stack_client import APIConnectionError, APIStatusError, AsyncLlamaStackClient

import constants
from client import AsyncLlamaStackClientHolder
from configuration import configuration
from constants import DEFAULT_RAG_TOOL
from log import get_logger
Expand Down Expand Up @@ -129,17 +128,11 @@

async def get_vector_store_ids(
client: AsyncLlamaStackClient,
vector_store_ids: Optional[list[str]] = None,
) -> list[str]:
Comment on lines 129 to 131

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Search for usages of get_vector_store_ids outside of its definition and tests.

rg -n -w 'get_vector_store_ids' -g '!tests/**' -g '!*test*.py'

Repository: lightspeed-core/lightspeed-stack

Length of output: 170


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the function definition and search all references, including tests and imports.
sed -n '1,220p' src/utils/responses.py
printf '\n--- REFERENCES ---\n'
rg -n -w 'get_vector_store_ids' .
printf '\n--- IMPORTS ---\n'
rg -n 'from\s+src\.utils\.responses\s+import|import\s+.*responses' . --glob '!**/__pycache__/**'

Repository: lightspeed-core/lightspeed-stack

Length of output: 9872


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '3000,3095p' tests/unit/utils/test_responses.py

Repository: lightspeed-core/lightspeed-stack

Length of output: 3750


Remove get_vector_store_ids and its dedicated tests
No production code references this helper anymore, so it can be deleted along with TestGetVectorStoreIds.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/responses.py` around lines 129 - 131, Delete the unused
get_vector_store_ids helper and remove its dedicated TestGetVectorStoreIds
tests. Verify no remaining references require updates, while leaving unrelated
response utilities and tests unchanged.

"""Get vector store IDs for querying.

If vector_store_ids are provided, returns them. Otherwise fetches all
available vector stores from Llama Stack.
"""Fetch all available vector stores from Llama Stack.

Args:
client: The AsyncLlamaStackClient to use for fetching stores
vector_store_ids: Optional list of vector store IDs. If provided,
returns this list. If None, fetches all available vector stores.

Returns:
List of vector store IDs to query
Expand All @@ -148,9 +141,6 @@ async def get_vector_store_ids(
HTTPException: With ServiceUnavailableResponse if connection fails,
or InternalServerErrorResponse if API returns an error status
"""
if vector_store_ids is not None:
return vector_store_ids

try:
vector_stores = await client.vector_stores.list()
return [vector_store.id for vector_store in vector_stores.data]
Expand Down Expand Up @@ -229,7 +219,6 @@ async def maybe_get_topic_summary(


async def prepare_tools( # pylint: disable=too-many-arguments,too-many-positional-arguments
client: AsyncLlamaStackClient,
vector_store_ids: Optional[list[str]],
no_tools: Optional[bool],
token: str,
Expand All @@ -239,9 +228,8 @@ async def prepare_tools( # pylint: disable=too-many-arguments,too-many-position
"""Prepare tools for Responses API including RAG and MCP tools.

Args:
client: The Llama Stack client instance
vector_store_ids: The list of vector store IDs to use for RAG tools
or None if all vector stores should be used
or None to fall back to rag.tool configuration
no_tools: Whether to skip tool preparation
token: Authentication token for MCP tools
mcp_headers: Per-request headers for MCP servers
Expand All @@ -259,22 +247,16 @@ async def prepare_tools( # pylint: disable=too-many-arguments,too-many-position
# Vector store ID resolution priority:
# 1. Per-request IDs: highest prio; customer-facing rag_ids are translated to vector_db_ids.
# 2. rag.tool config IDs: used when no per-request IDs provided, and rag.tool is configured.
# If rag.inline is configured, but not rag.tool, tool RAG is disabled.
# 3. All registered vector DBs: fallback when neither rag.tool nor rag.inline are configured.
# IDs fetched from llama-stack are already internal and need no translation.
byok_rags = configuration.configuration.byok_rag

is_tool_rag_enabled = len(configuration.configuration.rag.tool) > 0
is_inline_rag_enabled = len(configuration.configuration.rag.inline) > 0

if vector_store_ids is not None:
effective_ids = resolve_vector_store_ids(vector_store_ids, byok_rags)
elif is_tool_rag_enabled:
effective_ids = resolve_vector_store_ids(
configuration.configuration.rag.tool, byok_rags
)
elif not is_inline_rag_enabled:
effective_ids = await get_vector_store_ids(client, None)

# Add RAG tools if vector stores are available
rag_tools = get_rag_tools(effective_ids)
Expand Down Expand Up @@ -375,7 +357,6 @@ async def prepare_responses_params( # pylint: disable=too-many-arguments,too-ma

# Prepare tools for responses API
tools = await prepare_tools(
client,
query_request.vector_store_ids,
query_request.no_tools,
token,
Expand Down Expand Up @@ -1754,9 +1735,7 @@ async def _resolve_client_tools(

# Optionally merge server-configured tools (RAG, MCP) with client tools
if merge_server_tools:
client = AsyncLlamaStackClientHolder().get_client()
server_tools = await prepare_tools(
client=client,
vector_store_ids=vector_store_ids,
no_tools=False,
token=token,
Expand Down Expand Up @@ -1784,9 +1763,7 @@ async def _resolve_server_tools(
Returns:
List of server-configured tools, or None if none are configured.
"""
client = AsyncLlamaStackClientHolder().get_client()
return await prepare_tools(
client=client,
vector_store_ids=None, # allow all vector stores configured
no_tools=False,
token=token,
Expand Down Expand Up @@ -1830,9 +1807,7 @@ async def resolve_tool_choice(

if tools is None:
# Register all tools configured in LCORE configuration
client = AsyncLlamaStackClientHolder().get_client()
prepared_tools = await prepare_tools(
client=client,
vector_store_ids=None, # allow all vector stores configured
no_tools=False,
token=token,
Expand Down
49 changes: 46 additions & 3 deletions tests/integration/container_lifecycle/test_container_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import time
import urllib.error
import urllib.request
import warnings
from collections.abc import Generator

import pytest
Expand All @@ -18,13 +19,17 @@
CONTAINER_START_TIMEOUT = 300 # 5 minutes for container start
CONTAINER_STOP_TIMEOUT = 15
CONTAINER_CLEANUP_TIMEOUT = 10
IMAGE_CLEANUP_TIMEOUT = 30
DANGLING_IMAGES_CLEANUP_TIMEOUT = 300 # 5 minutes for dangling images cleanup
HEALTH_CHECK_TIMEOUT = 5
PORT_QUERY_TIMEOUT = 5

# Retry constants
HEALTH_CHECK_MAX_ATTEMPTS = 30
NETWORK_BINDING_MAX_ATTEMPTS = 5

DEFAULT_LIGHTSPEED_LLAMA_STACK_IMAGE_NAME = "lightspeed-llama-stack:local"


@pytest.fixture(scope="session")
def container_runtime() -> str:
Expand Down Expand Up @@ -52,6 +57,39 @@ def container_runtime() -> str:
pytest.skip("No container runtime available")


@pytest.fixture(scope="session", autouse=True)
def cleanup_container_artifacts(container_runtime: str) -> Generator[None]:
"""Remove container images and dangling layers after all tests complete.

Parameters
----------
container_runtime (str): Container runtime to use.

Yields
------
None
"""
yield

try:
subprocess.run(
[container_runtime, "rmi", "-f", DEFAULT_LIGHTSPEED_LLAMA_STACK_IMAGE_NAME],
capture_output=True,
timeout=IMAGE_CLEANUP_TIMEOUT,
)
except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e:
warnings.warn(f"Image cleanup failed: {e}")

try:
subprocess.run(
[container_runtime, "image", "prune", "-f"],
capture_output=True,
timeout=DANGLING_IMAGES_CLEANUP_TIMEOUT,
)
except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e:
warnings.warn(f"Dangling image cleanup failed: {e}")


@pytest.fixture(scope="class")
def managed_container(container_runtime: str) -> Generator[str, None, None]:
"""Start container once for entire test class with strict cleanup.
Expand Down Expand Up @@ -102,7 +140,7 @@ class TestContainerBuild:
"""Test container image building with idempotency checks."""

def _get_image_id(
self, runtime: str, image_name: str = "lightspeed-llama-stack:local"
self, runtime: str, image_name: str = DEFAULT_LIGHTSPEED_LLAMA_STACK_IMAGE_NAME
) -> str:
"""Get the unique, immutable Image ID (SHA256).

Expand Down Expand Up @@ -145,7 +183,7 @@ def test_build_llama_stack_image(self, container_runtime: str) -> None:

# Verify image is listed with correct tag
result = subprocess.run(
[container_runtime, "images", "lightspeed-llama-stack:local"],
[container_runtime, "images", DEFAULT_LIGHTSPEED_LLAMA_STACK_IMAGE_NAME],
capture_output=True,
text=True,
timeout=PORT_QUERY_TIMEOUT,
Expand Down Expand Up @@ -548,7 +586,12 @@ def test_clean_removes_image_and_container(self, container_runtime: str) -> None

# Verify image is removed
result = subprocess.run(
[container_runtime, "images", "-q", "lightspeed-llama-stack:local"],
[
container_runtime,
"images",
"-q",
DEFAULT_LIGHTSPEED_LLAMA_STACK_IMAGE_NAME,
],
capture_output=True,
text=True,
timeout=PORT_QUERY_TIMEOUT,
Expand Down
17 changes: 4 additions & 13 deletions tests/integration/endpoints/test_query_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# pylint: disable=too-many-arguments # Integration tests need many fixtures
# pylint: disable=too-many-positional-arguments # Integration tests need many fixtures


import pytest
from fastapi import HTTPException, Request, status
from llama_stack_client import APIConnectionError
Expand Down Expand Up @@ -676,14 +675,13 @@ async def test_query_v2_endpoint_bypasses_tools_when_no_tools_true(


@pytest.mark.asyncio
async def test_query_v2_endpoint_uses_tools_when_available(
async def test_query_v2_endpoint_uses_tools_when_available( # pylint: disable=unused-argument
test_config: AppConfig,
mock_llama_stack_client: AsyncMockType,
mock_query_agent: AsyncMockType,
test_request: Request,
test_auth: AuthTuple,
patch_db_session: Session,
mocker: MockerFixture,
) -> None:
"""Test that tools are used when no_tools=False and vector stores are available.

Expand All @@ -707,18 +705,11 @@ async def test_query_v2_endpoint_uses_tools_when_available(
-------
None
"""
_ = test_config
# prepare_tools does not require llama-stack client anymore so the way to
# enable RAG tools is through config
test_config.rag.tool = ["vs-test-123"]
_ = patch_db_session

# Mock vector stores to be available (simulating RAG tools)
mock_vector_store = mocker.MagicMock()
mock_vector_store.id = "vs-test-123"

mock_list_result = mocker.MagicMock()
mock_list_result.data = [mock_vector_store]

mock_llama_stack_client.vector_stores.list.return_value = mock_list_result

query_request = QueryRequest(query="What is Ansible?", no_tools=False)

response = await query_endpoint_handler(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ def _patch_all_client_holders(mocker: MockerFixture, mock_client: Any) -> None:
for module in (
"app.endpoints.responses",
"utils.endpoints",
"utils.responses",
):
holder = mocker.patch(f"{module}.AsyncLlamaStackClientHolder")
holder.return_value.get_client.return_value = mock_client
Expand Down
Loading
Loading