Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
6795224
feat: added tests
jacopo-chevallard Jun 2, 2025
cc2c5c0
feat: added tests
jacopo-chevallard Jun 2, 2025
2d28a5e
feat: added tests
jacopo-chevallard Jun 2, 2025
c1647c8
feat: beginning of major refacto
jacopo-chevallard Jun 2, 2025
0a8cd15
feat: continuing refactor
jacopo-chevallard Jun 5, 2025
d49f32f
feat: continuing refactor
jacopo-chevallard Jun 12, 2025
89eb50f
feat: reinit services when nos passed by the user and the service con…
jacopo-chevallard Jun 16, 2025
7c3deac
feat: simplified logic of retrieval nodes
jacopo-chevallard Jun 16, 2025
e561fd1
feat: adding utils
jacopo-chevallard Jun 16, 2025
37a936f
feat: adding further nodes
jacopo-chevallard Jun 16, 2025
82a1ed4
feat: continue dev
jacopo-chevallard Jun 17, 2025
f4ec01c
feat: enable node-specific config
jacopo-chevallard Jun 17, 2025
12d1fc7
feat: keep max_context_tokens as set, without subtracting max_output_…
jacopo-chevallard Jun 17, 2025
cfe71b5
feat: re-raise exceptions
jacopo-chevallard Jun 17, 2025
aaf7bd3
fix: adding missing scope
jacopo-chevallard Jun 17, 2025
dc151dd
fix: imports
jacopo-chevallard Jun 17, 2025
eef8674
feat: adding some unit tests
jacopo-chevallard Jun 17, 2025
222653a
feat: adding tests
jacopo-chevallard Jun 17, 2025
2035d6a
feat: adding tests
jacopo-chevallard Jun 17, 2025
22ea6c9
fix: tests
jacopo-chevallard Jun 17, 2025
dabfd51
feat: example use of new classes
jacopo-chevallard Jun 17, 2025
be9528e
feat: continue dev
jacopo-chevallard Jun 23, 2025
bfe0180
fix: fixing tests
jacopo-chevallard Jun 23, 2025
2a53ba1
feat: remove older files
jacopo-chevallard Jun 23, 2025
fadc523
feat: added test
jacopo-chevallard Jun 23, 2025
2ef6c75
feat: update brain
jacopo-chevallard Jun 23, 2025
459ab23
feat: separating configuration passed to similarity_search from extra…
jacopo-chevallard Jun 25, 2025
3faf116
feat: passing service_container
jacopo-chevallard Jun 25, 2025
301757c
fix: tests
jacopo-chevallard Jun 25, 2025
3e9bf06
fix: tests
jacopo-chevallard Jun 25, 2025
18dcba8
feat: fixing examples
jacopo-chevallard Jun 25, 2025
b125222
chore: fix CI to run tests
jacopo-chevallard Jun 25, 2025
a224c62
chore: fix CI to run tests
jacopo-chevallard Jun 25, 2025
d991846
chore: fix CI to run tests
jacopo-chevallard Jun 25, 2025
42e6e89
chore: fix CI to run tests
jacopo-chevallard Jun 25, 2025
1df3605
chore: fix CI to run tests
jacopo-chevallard Jun 25, 2025
f69ba34
chore: fix CI to run tests
jacopo-chevallard Jun 25, 2025
9de20f8
fix: example
jacopo-chevallard Jun 26, 2025
eb2cee3
feat: add LRU cache memory management to ServiceContainer
jacopo-chevallard Jun 26, 2025
6716817
chore: fix CI tests
jacopo-chevallard Jun 26, 2025
c743d80
Merge branch 'main' into feat/refacto_langgraph
jacopo-chevallard Jun 26, 2025
5948199
feat: added validation of node input states
jacopo-chevallard Jun 26, 2025
ca73329
feat: adding further tests
jacopo-chevallard Jun 26, 2025
fe5b681
fix: passing dict[str, str]
jacopo-chevallard Jun 26, 2025
c583647
Merge branch 'feat/refacto_langgraph' into feat/deep_generate_V0
jacopo-chevallard Jun 26, 2025
c9c3ba9
fix: fixing errors in passing node-specific configs
jacopo-chevallard Jun 27, 2025
f0e12c4
Merge branch 'feat/refacto_langgraph' into feat/deep_generate_V0
jacopo-chevallard Jun 27, 2025
834204a
feat: adding node to split tasks
jacopo-chevallard Jun 27, 2025
9b0c150
feat: use different pydantic models for split into tasks and split in…
jacopo-chevallard Jun 27, 2025
6afc323
feat: enable adding tasks to UserTasks and getting deduplicated docs
jacopo-chevallard Jun 27, 2025
b670b36
feat: adding prompt to split ticket into multiple tasks
jacopo-chevallard Jun 27, 2025
c55f54c
feat: add option to use cache
jacopo-chevallard Jun 30, 2025
485fd32
feat: do not recreate service / retriever
jacopo-chevallard Jun 30, 2025
fb72e49
feat: use same language as input in splitted task
jacopo-chevallard Jun 30, 2025
11e9302
feat: added prompt registry
jacopo-chevallard Jun 30, 2025
72e13f9
feat: remove modules superseded by prompt registry
jacopo-chevallard Jun 30, 2025
027fab7
feat: using newly created prompt registry
jacopo-chevallard Jun 30, 2025
3b6973c
feat: use prompt registry
jacopo-chevallard Jun 30, 2025
406b4f1
feat: remove prompt service, replaced by prompt registry
jacopo-chevallard Jun 30, 2025
e6d9df0
feat: add base registry class
jacopo-chevallard Jun 30, 2025
0a829a8
feat: refacto tool registry to use the base registry class
jacopo-chevallard Jul 1, 2025
9dd47ee
fix: remove old TemplatePromptName
jacopo-chevallard Jul 1, 2025
721cd00
feat: use common registry
jacopo-chevallard Jul 1, 2025
65717cf
feat: add tests for new prompt registry
jacopo-chevallard Jul 1, 2025
bb3c4e6
feat: fixing tests and adding new ones
jacopo-chevallard Jul 1, 2025
04c1487
feat: update tool use/configuration
jacopo-chevallard Jul 1, 2025
f807a0c
feat: avoid typing errors
jacopo-chevallard Jul 1, 2025
0720b9f
feat: continue dev
jacopo-chevallard Jul 2, 2025
1122746
feat: added config class for tools
jacopo-chevallard Jul 7, 2025
4280e05
refacto: moved to examples
jacopo-chevallard Jul 7, 2025
1ca8fd5
feat: use Pydantic settings
jacopo-chevallard Jul 7, 2025
4207be9
feat: fixing tests
jacopo-chevallard Jul 7, 2025
ff3d50c
feat: use generic to fix return type
jacopo-chevallard Jul 7, 2025
058b28b
feat: make service caching optional
jacopo-chevallard Jul 7, 2025
186df4b
fix: tests
jacopo-chevallard Jul 7, 2025
46eecfb
feat: rename class and module
jacopo-chevallard Jul 7, 2025
f7e7406
feat: move methods to utils
jacopo-chevallard Jul 7, 2025
13a12c2
feat: typing
jacopo-chevallard Jul 7, 2025
563e40f
feat: improve separation of concerns
jacopo-chevallard Jul 7, 2025
d7a605e
fix: linting
jacopo-chevallard Jul 7, 2025
773b125
fix: tests
jacopo-chevallard Jul 7, 2025
9a5c78d
fix: tests
jacopo-chevallard Jul 7, 2025
cde35dc
feat: adding tests
jacopo-chevallard Jul 7, 2025
8b58194
feat: adding tests
jacopo-chevallard Jul 7, 2025
14efd52
Merge branch 'feat/refacto_langgraph' into feat/deep_generate_V0
jacopo-chevallard Jul 9, 2025
9229cfe
feat: fixed tests
jacopo-chevallard Jul 9, 2025
358b06f
feat: enable passing runtime context to nodes/tools
jacopo-chevallard Jul 9, 2025
88037e9
feat: make workspace_id optional, but raise warning
jacopo-chevallard Jul 9, 2025
5d55072
fix: tests
jacopo-chevallard Jul 9, 2025
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
52 changes: 42 additions & 10 deletions .github/workflows/backend-core-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ name: Run Tests with Tika Server

on:
push:
paths:
- "core/**"
pull_request:
paths:
- "core/**"
workflow_dispatch:
# pull_request:
# workflow_dispatch:

env:
NATS_TOKEN: test

jobs:
test:
Expand All @@ -23,22 +22,55 @@ jobs:
- name: 👀 Checkout code
uses: actions/checkout@v2

- name: Setup apt cache
uses: actions/cache@v4
with:
path: /var/cache/apt/archives
key: ${{ runner.os }}-apt-${{ hashFiles('/etc/apt/sources.list') }}

- name: 😭 Install system dependencies
run: |
sudo apt-get update && \
sudo apt-get install -y libmagic-dev poppler-utils libreoffice tesseract-ocr pandoc

- name: 🔨 Install the latest version of rye
uses: eifinger/setup-rye@v4
with:
enable-cache: true
working-directory: backend

- name: 🔽 Download and Install NATS Server
run: |
curl -L https://github.com/nats-io/nats-server/releases/download/v2.10.22/nats-server-v2.10.22-linux-amd64.zip -o nats-server.zip
unzip nats-server.zip -d nats-server && sudo cp nats-server/nats-server-v2.10.22-linux-amd64/nats-server /usr/bin

- name: 🛠️ Set up NATS arguments
run: |
nohup nats-server \
--addr 0.0.0.0 \
--port 4222 \
--auth "$NATS_TOKEN" > nats.log 2>&1 &

- name: 🔍 Verify NATS Server is Running
run: |
sleep 1 # Give the server some time to start
if nc -zv localhost 4222; then
echo "✅ NATS Server is running on port 4222."
else
echo "❌ Failed to start NATS Server."
cat nats.log
exit 1
fi

- name: 🔄 Sync dependencies
run: |
cd core
UV_INDEX_STRATEGY=unsafe-first-match rye sync --no-lock

- name: Run tests
- name: 🚀 Run tests
env:
TIKA_URL: http://localhost:9998/tika
OPENAI_API_KEY: this-is-a-test-key
run: |
sudo apt-get update
sudo apt-get install -y libmagic-dev poppler-utils libreoffice tesseract-ocr pandoc
cd core
rye test -p quivr-core
rye test -p quivr_core -v
73 changes: 52 additions & 21 deletions core/quivr_core/brain/brain.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,25 @@
import os
from pathlib import Path
from pprint import PrettyPrinter
from typing import Any, AsyncGenerator, Callable, Dict, Self, Type, Union
from typing import Any, AsyncGenerator, Callable, Dict, Self, Union
from uuid import UUID, uuid4

from langchain_core.documents import Document
from langchain_core.embeddings import Embeddings
from langchain_core.messages import AIMessage, HumanMessage
from langchain_core.vectorstores import VectorStore
from langchain_openai import OpenAIEmbeddings
from quivr_core.rag.entities.prompt import PromptConfig
from quivr_core.rag.langgraph_framework.state import AgentState
from quivr_core.rag.langgraph_framework.base.extractors import ConfigMapping
from quivr_core.rag.langgraph_framework.entities.filter_history_config import (
FilterHistoryConfig,
)
from quivr_core.rag.langgraph_framework.services.llm_service import LLMService
from quivr_core.rag.langgraph_framework.services.service_container import (
ServiceContainer,
)
from quivr_core.rag.quivr_rag_langgraph import QuivrQARAGLangGraph
from rich.console import Console
from rich.panel import Panel

Expand All @@ -26,16 +37,19 @@
from quivr_core.llm import LLMEndpoint
from quivr_core.processor.registry import get_processor_class
from quivr_core.rag.entities.chat import ChatHistory
from quivr_core.rag.entities.config import RetrievalConfig
from quivr_core.rag.entities.config import (
LLMEndpointConfig,
RetrievalConfig,
RunTimeContext,
WorkflowConfig,
)
from quivr_core.rag.entities.models import (
LangchainMetadata,
ParsedRAGChunkResponse,
ParsedRAGResponse,
QuivrKnowledge,
SearchResult,
)
from quivr_core.rag.quivr_rag import QuivrQARAG
from quivr_core.rag.quivr_rag_langgraph import QuivrQARAGLangGraph
from quivr_core.storage.local_storage import LocalStorage, TransparentStorage
from quivr_core.storage.storage_base import StorageBase

Expand Down Expand Up @@ -119,12 +133,19 @@ def __init__(
storage: StorageBase | None = None,
workspace_id: UUID | None = None,
chat_id: UUID | None = None,
service_container: ServiceContainer | None = None,
):
self.id = id
self.name = name
self.storage = storage
self.workspace_id = workspace_id
self.chat_id = chat_id

# Service container
self.service_container = service_container
if not self.service_container:
self.service_container = ServiceContainer(vector_store=vector_db)

# Chat history
self._chats = self._init_chats()
self.default_chat = list(self._chats.values())[0]
Expand Down Expand Up @@ -500,7 +521,6 @@ async def ask_streaming(
run_id: UUID,
system_prompt: str | None = None,
retrieval_config: RetrievalConfig | None = None,
rag_pipeline: Type[Union[QuivrQARAG, QuivrQARAGLangGraph]] | None = None,
list_files: list[QuivrKnowledge] | None = None,
chat_history: ChatHistory | None = None,
**input_kwargs,
Expand All @@ -510,7 +530,6 @@ async def ask_streaming(
Args:
question (str): The question to ask.
retrieval_config (RetrievalConfig | None): The retrieval configuration (see RetrievalConfig docs).
rag_pipeline (Type[Union[QuivrQARAG, QuivrQARAGLangGraph]] | None): The RAG pipeline to use.
list_files (list[QuivrKnowledge] | None): The list of files to include in the RAG pipeline.
chat_history (ChatHistory | None): The chat history to use.
Returns:
Expand All @@ -522,17 +541,34 @@ async def ask_streaming(
print(chunk.answer)
```
"""
llm = self.llm

# If you passed a different llm model we'll override the brain one
if retrieval_config:
if retrieval_config.llm_config != self.llm.get_config():
llm = LLMEndpoint.from_config(config=retrieval_config.llm_config)
else:
# If you passed a different llm model we 'll override the brain one
if not retrieval_config:
retrieval_config = RetrievalConfig(llm_config=self.llm.get_config())

retrieval_config.runtime_context.workspace_id = self.workspace_id

workflow_config = retrieval_config.workflow_config
llm_config = retrieval_config.llm_config
assert self.service_container, "Service container is not set"
llm_service = self.service_container.get_service(LLMService, llm_config)
config_extractor = ConfigMapping(
{
PromptConfig: "prompt_config",
LLMEndpointConfig: "llm_config",
WorkflowConfig: "workflow_config",
FilterHistoryConfig: "filter_history_config",
RunTimeContext: "runtime_context",
}
)

rag_instance = QuivrQARAGLangGraph(
retrieval_config=retrieval_config, llm=llm, vector_store=self.vector_db
workflow_config=workflow_config,
graph_state=AgentState,
graph_config=retrieval_config.model_dump(),
graph_config_schema=RetrievalConfig,
llm_service=llm_service,
config_extractor=config_extractor,
service_container=self.service_container,
)

chat_history = self.default_chat if chat_history is None else chat_history
Expand All @@ -552,7 +588,8 @@ async def ask_streaming(
system_prompt=system_prompt or None,
history=chat_history,
list_files=list_files,
metadata=metadata,
workspace_id=self.workspace_id,
metadata=metadata.model_dump(),
**input_kwargs,
):
# Format output to be correct servicedf;j
Expand All @@ -571,7 +608,6 @@ async def aask(
question: str,
system_prompt: str | None = None,
retrieval_config: RetrievalConfig | None = None,
rag_pipeline: Type[Union[QuivrQARAG, QuivrQARAGLangGraph]] | None = None,
list_files: list[QuivrKnowledge] | None = None,
chat_history: ChatHistory | None = None,
**input_kwargs,
Expand All @@ -581,7 +617,6 @@ async def aask(
Args:
question (str): The question to ask.
retrieval_config (RetrievalConfig | None): The retrieval configuration (see RetrievalConfig docs).
rag_pipeline (Type[Union[QuivrQARAG, QuivrQARAGLangGraph]] | None): The RAG pipeline to use.
list_files (list[QuivrKnowledge] | None): The list of files to include in the RAG pipeline.
chat_history (ChatHistory | None): The chat history to use.
Returns:
Expand All @@ -596,7 +631,6 @@ async def aask(
question=question,
system_prompt=system_prompt,
retrieval_config=retrieval_config,
rag_pipeline=rag_pipeline,
list_files=list_files,
chat_history=chat_history,
**input_kwargs,
Expand All @@ -613,7 +647,6 @@ def ask(
question: str,
system_prompt: str | None = None,
retrieval_config: RetrievalConfig | None = None,
rag_pipeline: Type[Union[QuivrQARAG, QuivrQARAGLangGraph]] | None = None,
list_files: list[QuivrKnowledge] | None = None,
chat_history: ChatHistory | None = None,
) -> ParsedRAGResponse:
Expand All @@ -623,7 +656,6 @@ def ask(
question (str): The question to ask.
system_prompt (str | None): The system prompt to use.
retrieval_config (RetrievalConfig | None): The retrieval configuration (see RetrievalConfig docs).
rag_pipeline (Type[Union[QuivrQARAG, QuivrQARAGLangGraph]] | None): The RAG pipeline to use.
list_files (list[QuivrKnowledge] | None): The list of files to include in the RAG pipeline.
chat_history (ChatHistory | None): The chat history to use.
Returns:
Expand All @@ -636,7 +668,6 @@ def ask(
question=question,
system_prompt=system_prompt,
retrieval_config=retrieval_config,
rag_pipeline=rag_pipeline,
list_files=list_files,
chat_history=chat_history,
)
Expand Down
15 changes: 15 additions & 0 deletions core/quivr_core/llm_tools/base/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
Base classes for LLM tools with unified interface and lifecycle management.
"""

from .tool import (
QuivrBaseTool,
ToolConfig,
ToolResult,
)

__all__ = [
"QuivrBaseTool",
"ToolConfig",
"ToolResult",
]
Loading
Loading