diff --git a/.env.example b/.env.example index 6ac31ed..0e47d8c 100644 --- a/.env.example +++ b/.env.example @@ -8,15 +8,6 @@ POSTGRES_TABLE_NAME="documents" # General Configuration PORT="3001" -SIMILARITY_MEASURE="cosine" - -# LLM Provider Configuration -DEFAULT_CHAT_PROVIDER="gemini" -DEFAULT_CHAT_MODEL="Gemini Flash 2.5" -DEFAULT_FAST_CHAT_PROVIDER="gemini" -DEFAULT_FAST_CHAT_MODEL="Gemini Flash 2.5" -DEFAULT_EMBEDDING_PROVIDER="openai" -DEFAULT_EMBEDDING_MODEL="Text embedding 3 large" # LLM Provider API Keys OPENAI_API_KEY="" @@ -26,10 +17,6 @@ DEEPSEEK_API_KEY="" GROQ_API_KEY="" XAI_API_KEY="" -# Version Configuration -STARKNET_FOUNDRY_VERSION="0.47.0" -SCARB_VERSION="2.11.4" - # LangSmith Configuration (Optional) LANGSMITH_TRACING="false" LANGSMITH_ENDPOINT="https://api.smith.langchain.com" diff --git a/.github/workflows/generate-embeddings.yml b/.github/workflows/generate-embeddings.yml index 94689eb..5aad672 100644 --- a/.github/workflows/generate-embeddings.yml +++ b/.github/workflows/generate-embeddings.yml @@ -64,24 +64,12 @@ jobs: # General Configuration PORT="3001" - SIMILARITY_MEASURE="cosine" - - # Provider Configuration - DEFAULT_CHAT_PROVIDER="gemini" - DEFAULT_CHAT_MODEL="Gemini Flash 2.5" - DEFAULT_FAST_CHAT_PROVIDER="gemini" - DEFAULT_FAST_CHAT_MODEL="Gemini Flash 2.5" - DEFAULT_EMBEDDING_PROVIDER="openai" - DEFAULT_EMBEDDING_MODEL="Text embedding 3 large" # API Keys OPENAI_API_KEY="${{ secrets.OPENAI }}" ANTHROPIC_API_KEY="${{ secrets.ANTHROPIC }}" GEMINI_API_KEY="${{ secrets.GEMINI }}" - # Version Configuration - STARKNET_FOUNDRY_VERSION="0.47.0" - SCARB_VERSION="2.11.4" EOL - name: Generate embeddings diff --git a/README.md b/README.md index 3bab81d..0721460 100644 --- a/README.md +++ b/README.md @@ -66,9 +66,10 @@ Using Docker is highly recommended for a streamlined setup. Edit the `.env` file with your credentials: - - Database credentials (defaults provided for local development) - - LLM API keys (at least one required: OpenAI, Anthropic, or Gemini) - - Optional: LangSmith credentials for monitoring + - Database credentials (defaults provided above for local development) + - LLM API keys (at least one required: `GEMINI_API_KEY` is recommended) + - Optional: `XAI_API_KEY` for Grok search functionality + - Optional: `LANGSMITH_*` variables for monitoring 3. **Run the Ingester (First Time Setup)** @@ -120,12 +121,11 @@ Cairo Coder uses a modern architecture based on Retrieval-Augmented Generation ( ### Project Structure -The project is organized as a monorepo with multiple packages: +The project is organized as a monorepo with multiple components: - **python/**: The core RAG agent and API server implementation using DSPy and FastAPI. -- **packages/ingester/**: (TypeScript) Data ingestion tools for Cairo documentation sources. -- **packages/typescript-config/**: Shared TypeScript configuration. -- **(Legacy)** `packages/agents`: The original Langchain-based TypeScript implementation. +- **ingesters/**: (TypeScript/Bun) Data ingestion tools for Cairo documentation sources. +- **docker-compose.yml**: Orchestrates postgres, backend, and ingester services. ### RAG Pipeline (Python/DSPy) @@ -141,21 +141,48 @@ The RAG pipeline is implemented in the `python/src/cairo_coder/core/` directory ### Python Service -For local development of the Python service, navigate to `python/` and run the following commands` +For local development of the Python service: 1. **Setup Environment**: + + ```bash + cd python + + # Install uv package manager (if not already installed) + curl -LsSf https://astral.sh/uv/install.sh | sh + + # Install dependencies + uv sync + ``` + +2. **Start Database** (from root directory): + ```bash - # Install uv package manager - curl -LsSf https://astral.sh/uv/install.sh | sh + # From root directory + docker compose up postgres ``` -2. **Run Server**: - > Note: make sure the database is running, and the ingesters have been run. + +3. **Run Ingester** (first time setup, from root directory): + ```bash - uv run cairo-coder --dev + # From root directory + cd ingesters + bun install + bun run generate-embeddings:yes + cd .. ``` -3. **Run Tests & Linting**: + +4. **Run Server** (from python directory): + + ```bash + cd python + uv run cairo-coder --dev + ``` + +5. **Run Tests** (from python directory): ```bash - uv run pytest + cd python + uv run pytest ``` ### Starklings Evaluation @@ -165,11 +192,12 @@ A script is included to evaluate the agent's performance on the Starklings exerc > Note: we recommend pre-warming the compilation cache by running `cd fixtures/runner_crate && scarb build` before running the evaluation. ```bash -# Run a single evaluation round +# From python directory +cd python uv run starklings_evaluate ``` -Results are saved in the `starklings_results/` directory. +Results are saved in the `python/starklings_results/` directory. ## Contribution diff --git a/python/README.md b/python/README.md index eccfe81..4bb6423 100644 --- a/python/README.md +++ b/python/README.md @@ -18,7 +18,9 @@ Cairo Coder is an AI-powered code generation service specifically designed for t ## Installation ```bash -# Install uv package manager +cd python + +# Install uv package manager (if not already installed) curl -LsSf https://astral.sh/uv/install.sh | sh # Install dependencies @@ -31,8 +33,8 @@ Cairo Coder uses environment variables for all sensitive configuration like API ```bash # From the root directory -cp .env.example .env -# Edit .env with your credentials +# Create .env file with required environment variables +# See main README.md for required variables ``` ## Running the Service @@ -56,15 +58,26 @@ docker compose up postgres ```bash # From root directory -pnpm generate-embeddings +cd ingesters +bun install +bun run generate-embeddings:yes +cd .. ``` -4. Start the FastAPI server: +4. Start the FastAPI server (from python directory): ```bash +cd python uv run cairo-coder ``` +Or with development mode (auto-reload): + +```bash +cd python +uv run cairo-coder --dev +``` + ### Dockerized All configuration is handled automatically via Docker Compose. From the root directory: diff --git a/python/src/cairo_coder/config/manager.py b/python/src/cairo_coder/config/manager.py index f57f03d..6d31ef4 100644 --- a/python/src/cairo_coder/config/manager.py +++ b/python/src/cairo_coder/config/manager.py @@ -27,7 +27,6 @@ def load_config() -> Config: user=os.getenv("POSTGRES_USER", "cairocoder"), password=os.getenv("POSTGRES_PASSWORD", ""), table_name=os.getenv("POSTGRES_TABLE_NAME", "documents"), - similarity_measure=os.getenv("SIMILARITY_MEASURE", "cosine"), ) # Validate essential configuration diff --git a/python/src/cairo_coder/core/config.py b/python/src/cairo_coder/core/config.py index 95f2f4c..9b1ac44 100644 --- a/python/src/cairo_coder/core/config.py +++ b/python/src/cairo_coder/core/config.py @@ -13,8 +13,6 @@ class VectorStoreConfig: user: str password: str table_name: str - embedding_dimension: int = 2048 # text-embedding-3-large dimension - similarity_measure: str = "cosine" # cosine, dot_product, euclidean @property def dsn(self) -> str: diff --git a/python/src/cairo_coder/dspy/pgvector_rm.py b/python/src/cairo_coder/dspy/pgvector_rm.py index 9813b06..b6d8145 100644 --- a/python/src/cairo_coder/dspy/pgvector_rm.py +++ b/python/src/cairo_coder/dspy/pgvector_rm.py @@ -44,8 +44,8 @@ class PgVectorRM(dspy.Retrieve): llm = dspy.LM("gemini/gemini-flash-latest") dspy.configure(lm=llm) - # DATABASE_URL should be in the format postgresql://user:password@host/database - db_url = os.getenv("DATABASE_URL") + # DATABASE_URL should be in the format: + db_url = postgresql://user:password@host/database # embedding_func will default to dspy.settings.embedder retriever_model = PgVectorRM(db_url, "paragraphs", fields=["text", "document_id"], k=20) diff --git a/python/src/cairo_coder/server/app.py b/python/src/cairo_coder/server/app.py index 0970972..2045ce7 100644 --- a/python/src/cairo_coder/server/app.py +++ b/python/src/cairo_coder/server/app.py @@ -755,7 +755,6 @@ def get_vector_store_config() -> VectorStoreConfig: user=config.vector_store.user, password=config.vector_store.password, table_name=config.vector_store.table_name, - similarity_measure=config.vector_store.similarity_measure, ) diff --git a/python/tests/conftest.py b/python/tests/conftest.py index 93f57a7..7214b61 100644 --- a/python/tests/conftest.py +++ b/python/tests/conftest.py @@ -367,8 +367,6 @@ def clean_config_env_vars(monkeypatch): "POSTGRES_USER", "POSTGRES_PASSWORD", "POSTGRES_TABLE_NAME", - "POSTGRES_ROOT_DB", - "SIMILARITY_MEASURE", "HOST", "PORT", "DEBUG", diff --git a/python/tests/integration/test_config_integration.py b/python/tests/integration/test_config_integration.py index d776b44..bf5f00f 100644 --- a/python/tests/integration/test_config_integration.py +++ b/python/tests/integration/test_config_integration.py @@ -17,7 +17,6 @@ def test_load_configuration_from_env(self, monkeypatch: pytest.MonkeyPatch) -> N monkeypatch.setenv("POSTGRES_USER", "test_user") monkeypatch.setenv("POSTGRES_PASSWORD", "test_password") monkeypatch.setenv("POSTGRES_TABLE_NAME", "test_documents") - monkeypatch.setenv("SIMILARITY_MEASURE", "cosine") monkeypatch.setenv("HOST", "localhost") monkeypatch.setenv("PORT", "8001") monkeypatch.setenv("DEBUG", "true") @@ -31,7 +30,6 @@ def test_load_configuration_from_env(self, monkeypatch: pytest.MonkeyPatch) -> N assert config.vector_store.user == "test_user" assert config.vector_store.password == "test_password" assert config.vector_store.table_name == "test_documents" - assert config.vector_store.similarity_measure == "cosine" assert config.host == "localhost" assert config.port == 8001 assert config.debug is True diff --git a/python/tests/unit/test_config.py b/python/tests/unit/test_config.py index a47e50f..76fcba6 100644 --- a/python/tests/unit/test_config.py +++ b/python/tests/unit/test_config.py @@ -30,7 +30,6 @@ def test_load_config_with_defaults(self, monkeypatch: pytest.MonkeyPatch) -> Non assert config.vector_store.user == "cairocoder" assert config.vector_store.password == "test-password" assert config.vector_store.table_name == "documents" - assert config.vector_store.similarity_measure == "cosine" assert config.host == "0.0.0.0" assert config.port == 3001 assert config.debug is False @@ -44,7 +43,6 @@ def test_load_config_from_environment(self, monkeypatch: pytest.MonkeyPatch) -> monkeypatch.setenv("POSTGRES_USER", "env-user") monkeypatch.setenv("POSTGRES_PASSWORD", "env-pass") monkeypatch.setenv("POSTGRES_TABLE_NAME", "env-table") - monkeypatch.setenv("SIMILARITY_MEASURE", "dot_product") monkeypatch.setenv("HOST", "127.0.0.1") monkeypatch.setenv("PORT", "8080") monkeypatch.setenv("DEBUG", "true") @@ -58,7 +56,6 @@ def test_load_config_from_environment(self, monkeypatch: pytest.MonkeyPatch) -> assert config.vector_store.user == "env-user" assert config.vector_store.password == "env-pass" assert config.vector_store.table_name == "env-table" - assert config.vector_store.similarity_measure == "dot_product" assert config.host == "127.0.0.1" assert config.port == 8080 assert config.debug is True