Skip to content
Closed
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
16 changes: 8 additions & 8 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ jobs:
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
allowed_non_write_users: Copilot,copilot,jules[bot],jules
allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],copilot,github-actions,gemini[bot],claude[bot],jules[bot]"
allowed_non_write_users: ""
allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],github-actions,gemini[bot],claude[bot],jules[bot]"
trigger_phrase: "@claude"
assignee_trigger: claude[bot]
label_trigger: claude
Expand Down Expand Up @@ -105,8 +105,8 @@ jobs:
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
allowed_non_write_users: Copilot,copilot,jules[bot],jules
allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],copilot,github-actions,gemini[bot],claude[bot],jules[bot]"
allowed_non_write_users: ""
allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],github-actions,gemini[bot],claude[bot],jules[bot]"
trigger_phrase: "@claude"
assignee_trigger: claude
label_trigger: claude
Expand Down Expand Up @@ -142,8 +142,8 @@ jobs:
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
allowed_non_write_users: Copilot,copilot,jules[bot],jules
allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],copilot,github-actions,gemini[bot],claude[bot],jules[bot]"
allowed_non_write_users: ""
allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],github-actions,gemini[bot],claude[bot],jules[bot]"
trigger_phrase: "@claude"
assignee_trigger: claude
label_trigger: claude
Expand Down Expand Up @@ -181,8 +181,8 @@ jobs:
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
allowed_non_write_users: Copilot,copilot,jules[bot],jules
allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],copilot,github-actions,gemini[bot],claude[bot],jules[bot]"
allowed_non_write_users: ""
allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],github-actions,gemini[bot],claude[bot],jules[bot]"
trigger_phrase: "@claude"
assignee_trigger: claude
label_trigger: claude
Expand Down
4 changes: 2 additions & 2 deletions src/codeweaver/core/types/service_cards.py
Original file line number Diff line number Diff line change
Expand Up @@ -1268,11 +1268,11 @@ def _build_data_provider_cards() -> list[ServiceCard]:
service_card_factory(
"duckduckgo",
"data",
lateimport("codeweaver.providers.data.duckduckgo", "duckduckgo_search_tool"),
lateimport("pydantic_ai.common_tools.duckduckgo", "duck_duck_go_search_tool"),
lateimport("ddgs.ddgs", "DDGS"),
"duckduckgo",
metadata=ServiceMetadata(
# provider_cls is duckduckgo_search_tool; called with (client, **extra_kwargs)
# provider_cls is duck_duck_go_search_tool; called with (client, **extra_kwargs)
provider_handler=lambda provider_cls, card, client=None, **kwargs: provider_cls(
client, max_results=15
)
Expand Down
10 changes: 5 additions & 5 deletions src/codeweaver/providers/config/clients/multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,27 +43,27 @@
)


if has_package("google") is not None:
if has_package("google"):
from google.auth.credentials import Credentials as GoogleCredentials
else:
GoogleCredentials = Any
Comment on lines +46 to 49

if has_package("fastembed") is not None or has_package("fastembed_gpu") is not None:
if has_package("fastembed") or has_package("fastembed-gpu"):
try:
from fastembed.common.types import OnnxProvider
except ImportError:
OnnxProvider = Any # type: ignore[assignment, misc]
else:
OnnxProvider = Any # type: ignore[assignment, misc]

if has_package("torch") is not None:
if has_package("torch"):
try:
from torch.nn import Module
except ImportError:
Module = Any # type: ignore[assignment, misc]
else:
Module = Any # type: ignore[assignment, misc]
if has_package("sentence_transformers") is not None:
if has_package("sentence_transformers"):
# SentenceTransformerModelCardData contains these forward references:
# - eval_results_dict: dict[SentenceEvaluator, dict[str, Any]] | None
# - model: SentenceTransformer | None
Expand Down Expand Up @@ -521,7 +521,7 @@ def _telemetry_keys(self) -> dict[FilteredKeyT, AnonymityConversion]:
# Rebuild Pydantic models to resolve forward references after all imports complete
# This is necessary because SentenceTransformerModelCardData contains SentenceEvaluator references
if (
has_package("sentence_transformers") is not None
has_package("sentence_transformers")
and not SentenceTransformersClientOptions.__pydantic_complete__
):
# we can rebuild lazily later if this fails
Expand Down
10 changes: 5 additions & 5 deletions src/codeweaver/providers/config/profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,11 @@ def _quickstart_default(
agent_config=AnthropicAgentModelConfig(anthropic_thinking={"type": "disabled"}),
),
),
data=(TavilyProviderSettings(provider=Provider.TAVILY),)
if has_package("tavily") and Provider.TAVILY.has_env_auth
else (DuckDuckGoProviderSettings(provider=Provider.DUCKDUCKGO),)
if has_package("ddgs")
else (),
data=(
TavilyProviderSettings(provider=Provider.TAVILY)
if has_package("tavily") and Provider.TAVILY.has_env_auth
else DuckDuckGoProviderSettings(provider=Provider.DUCKDUCKGO),
),
vector_store=(
QdrantVectorStoreProviderSettings(
provider=Provider.QDRANT,
Expand Down
3 changes: 0 additions & 3 deletions src/codeweaver/providers/vector_stores/inmemory.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,6 @@ async def _persist_to_disk(self) -> None:
await temp_path.unlink()

try:
# Ensure parent directory exists before creating Qdrant client
await temp_path.parent.mkdir(parents=True, exist_ok=True)

# Initialize persistent client at temp path
# We use AsyncQdrantClient with path to create local storage
dest_client = AsyncQdrantClient(path=str(temp_path))
Expand Down
90 changes: 10 additions & 80 deletions tests/unit/core/test_discovery.py
Original file line number Diff line number Diff line change
@@ -1,88 +1,18 @@
# SPDX-FileCopyrightText: 2026 Knitli Inc.
# SPDX-FileContributor: Adam Poulemanos <adam@knit.li>
#
# SPDX-License-Identifier: MIT OR Apache-2.0

"""Unit tests for core discovery logic."""

from pathlib import Path
from unittest.mock import patch

import pytest

from codeweaver.core.discovery import DiscoveredFile
from codeweaver.core.metadata import ExtCategory


pytestmark = [pytest.mark.unit]


@pytest.fixture
def temp_project(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
"""Fixture to provide a temporary project directory and set the environment variable."""
project_dir = tmp_path / "project"
project_dir.mkdir()
monkeypatch.setenv("CODEWEAVER_PROJECT_PATH", str(project_dir))
return project_dir


def test_absolute_path_when_path_is_absolute() -> None:
"""Test absolute_path property when the file path is already absolute."""
abs_path = Path("/tmp/some_absolute_file.txt").resolve()
df = DiscoveredFile(
path=abs_path,
ext_category=ExtCategory.from_file(abs_path),
project_path=Path("/tmp/project")
)
result = df.absolute_path
assert result == abs_path


def test_absolute_path_when_path_is_relative_and_project_path_set() -> None:
"""Test absolute_path property when the file path is relative and project_path is set."""
rel_path = Path("src/main.py")
proj_path = Path("/home/user/project")
df = DiscoveredFile(
path=rel_path,
ext_category=ExtCategory.from_file(rel_path),
project_path=proj_path
def test_absolute_path_filenotfound() -> None:
"""Test that absolute_path falls back to returning self.path if get_project_path raises FileNotFoundError."""
# Setup our discovered file
file = DiscoveredFile(
path=Path("some/file.py"),
project_path=None
)
result = df.absolute_path
assert result == proj_path / rel_path


def test_absolute_path_when_project_path_is_none_success(temp_project: Path) -> None:
"""Test absolute_path property when project_path is falsy and get_project_path succeeds."""
rel_path = Path("src/main.py")
df = DiscoveredFile(
path=rel_path,
ext_category=ExtCategory.from_file(rel_path),
project_path=temp_project
)
# The property checks `if self.project_path:`. We can fake this by setting it to empty.
object.__setattr__(df, "project_path", "")

result = df.absolute_path

# It should fall back to get_project_path() which is temp_project due to the fixture
assert result == temp_project / rel_path


@patch('codeweaver.core.utils.get_project_path')
def test_absolute_path_when_project_path_is_none_filenotfound(mock_get_project_path) -> None:
"""Test absolute_path property when project_path is falsy and get_project_path raises FileNotFoundError."""
mock_get_project_path.side_effect = FileNotFoundError()

rel_path = Path("src/main.py")
df = DiscoveredFile(
path=rel_path,
ext_category=ExtCategory.from_file(rel_path),
project_path=Path("/tmp")
)
# The property checks `if self.project_path:`. We can fake this by setting it to empty.
object.__setattr__(df, "project_path", "")

result = df.absolute_path

# It should catch FileNotFoundError and return self.path
assert result == rel_path
# We want to mock get_project_path to raise FileNotFoundError
with patch("codeweaver.core.utils.get_project_path", side_effect=FileNotFoundError):
# We expect absolute_path to fall back to returning self.path
assert file.absolute_path == Path("some/file.py")
131 changes: 0 additions & 131 deletions tests/unit/test_init.py

This file was deleted.

Loading