You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Introduce LLMClient as the core entry point with named provider aliases,
os.environ/ resolution, and lazy instance caching. Replace the global
provider cache and if/elif routing with a registry pattern. Add Azure
OpenAI and Azure AI Foundry providers. Type tool_calls with Pydantic
models, add ChatMessage TypedDict, and per-provider message validation.
- Fix Google provider system message bug (was reading from params)
- Add gemini/ as alias for google/ prefix (backward compat)
- Bare model names default to openai (e.g. "gpt-4o")
- 67 functional tests parametrized across all 5 providers
- Per-provider CI matrix with conditional env var injection
- Comprehensive provider docstrings per 04-provider-docs.mdc
Made-with: Cursor
description: Architecture and design principles for giskard-llm. Always read before modifying providers, routing, or error handling.
3
+
alwaysApply: true
4
+
---
5
+
6
+
# giskard-llm Architecture
7
+
8
+
## Overview
9
+
10
+
`giskard-llm` is a lightweight routing layer that dispatches `"provider/model"` strings to native LLM SDKs. It replaces litellm with direct SDK calls while presenting a unified response shape to consumers.
11
+
12
+
## Architecture
13
+
14
+
The public API (`acompletion`, `aembedding`) routes `"provider/model"` strings through a lazy-loading registry to provider implementations. Providers are self-contained modules under `providers/`, each subclassing a shared ABC and responsible for: role mapping, message validation, tool conversion, error mapping, and response normalization.
15
+
16
+
Shared contracts live at the package root: Pydantic v2 response types (OpenAI-shaped), a unified error hierarchy with `status_code` for consumer retry logic, and a `should_retry` helper.
17
+
18
+
## Core Principles
19
+
20
+
1. **Lazy imports.** Importing `giskard.llm` must never require any provider SDK. SDKs are imported inside provider modules only.
21
+
2. **Strict message validation.** Providers validate messages before calling the SDK and raise `BadRequestError` with a clear message. Invalid input must not silently pass through to opaque SDK errors. Opt-in relaxation (e.g., `merge_system=True`) is explicit.
22
+
3. **Unified error boundary.** Raw SDK exceptions never escape a provider. Every provider maps its SDK errors to the `errors.py` hierarchy.
23
+
4. **Response normalization.** All providers convert native responses to the shared `types.py` models. Consumers never see provider-specific shapes.
24
+
5. **Provider config via env vars or `**params`.** The public API has no provider-specific kwargs. Configuration flows through environment variables or pass-through params.
25
+
6. **Provider behavior is self-documented.** Each provider class must have a comprehensive docstring covering: env vars, role mapping, error mapping, supported features, and provider-specific kwargs. This is the source of truth for provider behavior.
description: Testing conventions for giskard-llm. Read before writing or modifying tests.
3
+
globs: "**/test*.py,**/conftest.py"
4
+
---
5
+
6
+
# giskard-llm Testing Conventions
7
+
8
+
## Test Structure
9
+
10
+
- **Unit tests** (`tests/`): Mocked SDK calls, no API keys needed. Cover routing, message conversion, error mapping, response conversion, validation.
11
+
- **Functional tests** (`tests/functional/`): Real API calls. Cover end-to-end scenarios across all providers.
12
+
13
+
## Provider Marks and Auto-Skip
14
+
15
+
Every functional test is marked with its provider (`@pytest.mark.google`, `@pytest.mark.openai`, etc.). Auto-skip logic in `conftest.py` skips tests whose provider SDK is not installed, so unit test runs never fail due to missing optional dependencies.
16
+
17
+
## Scenario Design
18
+
19
+
- **Assert on structure, not content.** Tests must pass with even the weakest model. Assert non-empty responses, correct roles, correct types, parseable JSON — never assert on specific wording.
20
+
- **Meaningful inputs and outputs.** Test scenarios should exercise real behavior: system prompts that produce verifiable effects, tool calls with checkable arguments, structured output that validates against a schema. The goal is a test that fails for the right reasons.
description: Development workflow for giskard-llm. Read before creating a PR.
3
+
alwaysApply: false
4
+
---
5
+
6
+
# giskard-llm Development Workflow
7
+
8
+
## Dependencies
9
+
10
+
- **Core**: `pydantic>=2.0` only. No other runtime dependencies.
11
+
- **Provider SDKs**: Optional extras in `pyproject.toml` (`openai`, `google`, `anthropic`, `azure`). Never add a provider SDK to core.
12
+
- **Package manager**: `uv`.
13
+
14
+
## Format and Lint
15
+
16
+
`ruff format` and `ruff check` via pre-commit hooks. If `basedpyright` fails on provider files due to uninstalled SDKs, add `# pyright: reportMissingImports=false` at the top of the provider file.
17
+
18
+
## CI
19
+
20
+
- **Unit tests**: run on every PR, no SDK required — all provider interactions are mocked.
21
+
- **Functional tests**: run per-provider in a matrix. Each matrix entry installs only its SDK and injects only its env vars at the step level.
22
+
- **`workflow_dispatch`**: allows manual triggering with org-membership check.
23
+
24
+
## Commit Messages
25
+
26
+
Semantic format scoped to the lib: `feat(giskard-llm): add azure provider`, `fix(giskard-llm): google system message extraction`.
description: Provider documentation standards. Read when creating or modifying a provider.
3
+
globs: "**/providers/*.py"
4
+
---
5
+
6
+
# Provider Documentation
7
+
8
+
Each provider class must have a comprehensive docstring that serves as the single source of truth for that provider's behavior. This replaces external documentation that would go stale.
9
+
10
+
## Required Docstring Sections
11
+
12
+
Every provider class docstring must cover:
13
+
14
+
1. **Overview** — SDK used, what model prefix routes here (e.g., `"google/"`, `"azure/"`).
15
+
2. **Authentication** — Required env vars (e.g., `GOOGLE_API_KEY`) and alternative kwargs.
16
+
3. **Role mapping** — How canonical roles (`system`, `user`, `assistant`, `tool`) map to the SDK format.
Lightweight LLM routing layer over native provider SDKs. Routes `provider/model` strings to OpenAI, Google Gemini, or Anthropic using their native async SDKs.
3
+
Lightweight LLM routing layer over native provider SDKs. Routes `provider/model` strings to the correct async SDK (OpenAI, Google Gemini, Anthropic, Azure OpenAI, Azure AI Foundry).
4
4
5
5
## Installation
6
6
7
7
```bash
8
-
pip install giskard-llm[openai] # OpenAI only
9
-
pip install giskard-llm[google] # Google Gemini only
10
-
pip install giskard-llm[anthropic] # Anthropic only
For detailed per-provider documentation (role mapping, message constraints, tool format, error mapping), see the provider class docstrings in `src/giskard/llm/providers/`.
0 commit comments