diff --git a/CLAUDE.md b/CLAUDE.md index 46075236d..e180b0db2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -133,7 +133,7 @@ The RAG pipeline filters out false-positive sources by having the LLM self-repor 1. `format_context()` (`openrag/core/prompts/chat_prompt_builder.py`) numbers each source (`[Source 1]`, `[Source 2]`, ...) in the context and returns `(formatted_text, included_indices)` — the indices track which docs fit within the token budget 2. Prompt templates (`openrag/prompts/templates/*.txt`) instruct the LLM to append `[Sources: 1, 3, 5]` at the end of its response 3. `extract_and_strip_sources_block()` (`openrag/core/utils/source_filtering.py`) strips this tag from the response before sending to the client -4. `filter_sources_by_citations()` (`openrag/core/utils/source_filtering.py`) filters the source metadata to only include cited sources; if no `[Sources: ...]` tag is found at all, every retrieved source is kept instead (a missing tag means the model didn't report citations, not that it used none) +4. `filter_sources_by_citations()` (`openrag/core/utils/source_filtering.py`) filters the source metadata to only include cited sources; if no `[Sources: ...]` tag is found at all, every presented source is kept instead (a missing tag means the model didn't report citations, not that it used none) 5. For streaming, the OpenAI router buffers the last 100 chars to catch the sources tag before it reaches the client The `extra` field in API responses is a JSON string with these keys: diff --git a/infra/charts/openrag-stack/Chart.yaml b/infra/charts/openrag-stack/Chart.yaml index 557bbbd0a..deea0a96a 100644 --- a/infra/charts/openrag-stack/Chart.yaml +++ b/infra/charts/openrag-stack/Chart.yaml @@ -3,8 +3,8 @@ name: openrag-stack description: A Helm chart for Kubernetes type: application -version: 0.6.1 -appVersion: "2.1.0" +version: 0.6.2 +appVersion: "2.1.1" maintainers: - name: linagora diff --git a/infra/charts/openrag-stack/templates/raycluster.yaml b/infra/charts/openrag-stack/templates/raycluster.yaml index a63a01068..b8474cba9 100644 --- a/infra/charts/openrag-stack/templates/raycluster.yaml +++ b/infra/charts/openrag-stack/templates/raycluster.yaml @@ -37,6 +37,9 @@ spec: # Keep venv writes group-writable (GID 0) so a later sync under a # different APP_UID can still remove/replace owner-only entries # left by a previous sync. See infra/scripts/entrypoint.sh. + # NOTE: only fixes files written from here on — a PVC provisioned + # before this fix still has owner-only entries and needs to be + # recreated once after upgrading. umask 002 if [ -f /app/.venv/.ready ]; then echo "Existing env detected, skipping install." diff --git a/infra/charts/openrag-stack/values.yaml b/infra/charts/openrag-stack/values.yaml index 23e52e495..59d8c08d5 100644 --- a/infra/charts/openrag-stack/values.yaml +++ b/infra/charts/openrag-stack/values.yaml @@ -99,7 +99,7 @@ ray: registry: "ghcr.io" repository: "linagora/openrag-ray" # Pin to a release tag (ideally a digest) for reproducible deploys. - tag: "v2.1.0" + tag: "v2.1.1" resources: head: requests: @@ -383,7 +383,7 @@ adminUi: repository: "linagoraai/openrag-admin-ui" # Pin to a release tag (ideally a digest) for reproducible deploys. Must be a # build from infra/docker/ui.Dockerfile (nginx-unprivileged, listens :8080). - tag: "v2.1.0" + tag: "v2.1.1" pullPolicy: IfNotPresent replicaCount: 1 service: @@ -440,7 +440,7 @@ openrag: registry: "" repository: "linagoraai/openrag" # Pin to a release tag (ideally a digest) for reproducible deploys. - tag: "v2.1.0" + tag: "v2.1.1" pullPolicy: IfNotPresent service: type: ClusterIP diff --git a/infra/compose/docker-compose.yaml b/infra/compose/docker-compose.yaml index 38d1bb3a4..5a6d1a1b9 100644 --- a/infra/compose/docker-compose.yaml +++ b/infra/compose/docker-compose.yaml @@ -18,7 +18,7 @@ x-openrag-env: &openrag_env FONT_PATH: ${FONT_PATH:-/app/data/fonts/GoNotoCurrent-Regular.ttf} x-openrag: &openrag_template - image: linagoraai/openrag:v2.1.0 + image: linagoraai/openrag:v2.1.1 # Start as root so entrypoint.sh can grant GID-0 write on the bind-mounted # writable dirs (data/, logs/, the HF cache) — which a non-root container # can't write when Docker auto-creates them root-owned — then it immediately @@ -113,7 +113,7 @@ x-vllm: &vllm_template services: # ── Admin UI (React SPA + nginx, same-origin reverse proxy to the API) ── admin-ui: - image: linagoraai/openrag-admin-ui:v2.1.0 + image: linagoraai/openrag-admin-ui:v2.1.1 build: context: ../.. dockerfile: infra/docker/ui.Dockerfile diff --git a/infra/scripts/entrypoint.sh b/infra/scripts/entrypoint.sh index 3df3fbc12..38298cc98 100644 --- a/infra/scripts/entrypoint.sh +++ b/infra/scripts/entrypoint.sh @@ -37,6 +37,9 @@ fi # entries owner-writable only, so a later sync under a different UID can't # remove/replace them ("Permission denied" on __editable__*.pth). Force # group-writable new files/dirs so any GID-0 UID can always resync. +# NOTE: this only fixes files written from here on — an openrag_venv volume +# that already existed before this fix still has owner-only entries and needs +# to be recreated once after upgrading (delete the volume / let it resync). umask 002 ENV_ARGS=() diff --git a/openrag/services/orchestrators/query_service.py b/openrag/services/orchestrators/query_service.py index 8133f9028..882c8eeff 100644 --- a/openrag/services/orchestrators/query_service.py +++ b/openrag/services/orchestrators/query_service.py @@ -669,7 +669,7 @@ async def chat( ) -> dict: """Non-streaming chat completion → finalized OpenAI dict.""" metadata = payload.get("metadata") or {} - include_all_retrieved = bool(metadata.get("include_all_retrieved_sources", False)) + include_all_retrieved = metadata.get("include_all_retrieved_sources") is True llm = self._resolve_llm(partitions) citation_protocol_active = False if partitions is None and not metadata.get("websearch", False): @@ -717,7 +717,7 @@ async def chat_stream( ) -> AsyncIterator[str]: """Streaming chat completion → SSE strings with filtered sources.""" metadata = payload.get("metadata") or {} - include_all_retrieved = bool(metadata.get("include_all_retrieved_sources", False)) + include_all_retrieved = metadata.get("include_all_retrieved_sources") is True llm = self._resolve_llm(partitions) citation_protocol_active = False if partitions is None and not metadata.get("websearch", False): @@ -756,7 +756,7 @@ async def complete( ) -> dict: """Non-streaming text completion → finalized OpenAI dict.""" metadata = payload.get("metadata") or {} - include_all_retrieved = bool(metadata.get("include_all_retrieved_sources", False)) + include_all_retrieved = metadata.get("include_all_retrieved_sources") is True llm = self._resolve_llm(partitions) citation_protocol_active = partitions is not None if partitions is None: diff --git a/pyproject.toml b/pyproject.toml index a312607a9..c0db9d14f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openrag" -version = "2.1.0" +version = "2.1.1" description = "Add your description here" readme = "README.md" requires-python = ">=3.12" diff --git a/uv.lock b/uv.lock index 5dfa8b8f1..9b10a8e6f 100644 --- a/uv.lock +++ b/uv.lock @@ -2713,7 +2713,7 @@ wheels = [ [[package]] name = "openrag" -version = "2.1.0" +version = "2.1.1" source = { editable = "." } dependencies = [ { name = "aiobreaker" },