From dddab5ffb138e5bcc03d3f926f85e5f17c39cbc4 Mon Sep 17 00:00:00 2001 From: ernestprovo23 Date: Mon, 8 Jun 2026 22:39:34 -0400 Subject: [PATCH] docs: bump version to v0.3, scrub LiteLLM docstrings, sync doc index - bump package version 0.1.0 -> 0.3.0 (pyproject.toml + __init__.py) to match the shipped v0.3 provider-highway refactor - reword stale LiteLLM docstrings in council/registry/config/models to describe conclave's own provider-prefixed model-id convention (no code change); keep the accurate historical note in providers.py - DOCUMENTATION_INDEX: version 0.3.0; add test rows (test_cli, test_transport, test_logging); add community-file rows (SECURITY/CONTRIBUTING/CODE_OF_CONDUCT); add engineering-health backlog version-history row closes #21 --- DOCUMENTATION_INDEX.md | 9 ++++++++- pyproject.toml | 2 +- src/conclave/__init__.py | 2 +- src/conclave/config.py | 4 ++-- src/conclave/council.py | 4 ++-- src/conclave/models.py | 6 +++--- src/conclave/registry.py | 10 +++++----- 7 files changed, 22 insertions(+), 15 deletions(-) diff --git a/DOCUMENTATION_INDEX.md b/DOCUMENTATION_INDEX.md index e678e26..11509c2 100644 --- a/DOCUMENTATION_INDEX.md +++ b/DOCUMENTATION_INDEX.md @@ -6,7 +6,7 @@ context diagram, and this index linking everything together. The Product Design the canonical authority spec on top of those. - **Repo:** `/Users/ernestprovo/dev/conclave/` -- **Version:** 0.1.0 (package) · **License:** MIT +- **Version:** 0.3.0 · **License:** MIT - **Last updated:** 2026-06-08 --- @@ -60,6 +60,9 @@ Package root: `src/conclave/` (installed as the `conclave` package; console scri | Adapter tests | [`tests/test_adapters.py`](tests/test_adapters.py) | Per-adapter `build_request` + `parse_response` for openai-compat/anthropic/gemini: system-hoist, max_tokens, role mapping, usage parsing, empty/malformed/error-status raises. | | Provider highway tests | [`tests/test_providers.py`](tests/test_providers.py) | `resolve_adapter` (built-in prefixes, per-provider URLs, custom endpoints, unknown-prefix raise), end-to-end `call_model`, and `redact()` (bearer/`sk-`/env-var-value/`x-api-key` scrubbing; pre-redacted provider errors). | | Registry/config tests | [`tests/test_registry_config.py`](tests/test_registry_config.py) | Name resolution, key-presence logic, config merge. | +| CLI tests | [`tests/test_cli.py`](tests/test_cli.py) | Typer `CliRunner`: exit-code contract (0 success / 1 zero-usable-answers / 2 usage error), `--json` payload + exit code, human renderers per mode, `providers` table never prints secrets, aclose lifecycle. | +| Transport tests | [`tests/test_transport.py`](tests/test_transport.py) | `post_json` via httpx `MockTransport`: success/error-status/non-JSON fallback, timeout & connect/HTTP errors → `TransportError` (key never leaks), client reuse/pooling, aclose idempotency. | +| Logging tests | [`tests/test_logging.py`](tests/test_logging.py) | `CONCLAVE_LOG_LEVEL` resolution (default `WARNING`, case-insensitive, unknown → `WARNING`), factory contract, one-shot configuration. | | Fixtures | [`tests/conftest.py`](tests/conftest.py) | Shared fixtures; mocks the httpx transport so the suite needs no network and no API keys. | Run: `pytest` (config in `pyproject.toml`, `asyncio_mode = "auto"`). @@ -70,6 +73,9 @@ Run: `pytest` (config in `pyproject.toml`, `asyncio_mode = "auto"`). |------|------|---------| | Packaging | [`pyproject.toml`](pyproject.toml) | hatchling build, deps (httpx, pydantic, rich, typer, pyyaml — no LLM SDK), dev extras, console script, pytest config. License: MIT. | | License | [`LICENSE`](LICENSE) | MIT License. Copyright (c) 2026 Ernest Provo. Matches the `pyproject.toml` license field. | +| Security policy | [`SECURITY.md`](SECURITY.md) | BYO-keys vulnerability reporting policy: how to report, scope, and the key-handling guarantees consumers can rely on. | +| Contributing guide | [`CONTRIBUTING.md`](CONTRIBUTING.md) | Dev setup, the BYO-keys contract for contributors, and the PR checklist (tests, ruff lint/format, coverage). | +| Code of conduct | [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) | Contributor Covenant v2.1. | --- @@ -83,6 +89,7 @@ Run: `pytest` (config in `pyproject.toml`, `asyncio_mode = "auto"`). | Date | Change | |------|--------| +| 2026-06-08 | v0.3.0 version bump; CI foundation (Actions matrix, ruff, coverage floor, gitleaks, branch protection); redact() custom-endpoint key-leak fix (#14); status_error consolidation + conditional temperature (#16/#22); provider-metadata single-source + import-time drift guard + config memoization (#19/#15); CLI exit-code contract + httpx client lifecycle (#17/#20); transport/cli/logging test backfill (#18); public release + community files. | | 2026-06-08 | PDD §11 repositioned vs. new direct peers (`llm-council-core`, `the-llm-council`); §12 Q1/Q3/Q4/Q5 resolved. Index Tests table updated for the PR #2 split (`test_adapters.py`, `test_providers.py`). | | 2026-06-07 | v0.3 provider-highway refactor (LiteLLM removed → owned httpx transport + adapter registry); 3-core docs + PDD authored. | diff --git a/pyproject.toml b/pyproject.toml index d5132c0..653c17e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "conclave" -version = "0.1.0" +version = "0.3.0" description = "Bring-your-own-keys multi-model council CLI + library. Fan a prompt to N foundation models concurrently and merge their answers." readme = "README.md" requires-python = ">=3.11" diff --git a/src/conclave/__init__.py b/src/conclave/__init__.py index d866e08..9f67584 100644 --- a/src/conclave/__init__.py +++ b/src/conclave/__init__.py @@ -43,7 +43,7 @@ ) from .transport import aclose -__version__ = "0.1.0" +__version__ = "0.3.0" __all__ = [ "Council", diff --git a/src/conclave/config.py b/src/conclave/config.py index cced930..e70690e 100644 --- a/src/conclave/config.py +++ b/src/conclave/config.py @@ -70,10 +70,10 @@ class ConclaveConfig(BaseModel): endpoints: dict[str, CustomEndpoint] = Field(default_factory=dict) def resolve_model_id(self, name: str) -> str: - """Map a friendly name to a LiteLLM model id. + """Map a friendly name to a provider-prefixed model id. If ``name`` is unknown it is passed through verbatim, so a user can name - a council member by a raw LiteLLM id (e.g. ``"openai/gpt-4o"``). + a council member by a raw provider-prefixed id (e.g. ``"openai/gpt-4o"``). """ return self.models.get(name, name) diff --git a/src/conclave/council.py b/src/conclave/council.py index 51c1742..da6beab 100644 --- a/src/conclave/council.py +++ b/src/conclave/council.py @@ -1,7 +1,7 @@ """The Council: concurrent multi-model fan-out plus synthesis. ``Council`` is the primary importable entry point. It resolves friendly names to -LiteLLM model ids, skips any member whose API key is absent, fans the prompt out +provider-prefixed model ids, skips any member whose API key is absent, fans the prompt out concurrently, collects partial results even when some members fail, and (in synthesize mode) asks a synthesizer model to merge the answers into one. @@ -42,7 +42,7 @@ class Council: """A council of foundation models with an optional synthesizer. Args: - models: Friendly names (or raw LiteLLM ids) of council members. + models: Friendly names (or raw provider-prefixed model ids) of council members. synthesizer: Friendly name of the synthesizer model. If ``None``, the config default is used. config: Pre-loaded config; if ``None``, loaded from disk + defaults. diff --git a/src/conclave/models.py b/src/conclave/models.py index 25803b8..4abbd66 100644 --- a/src/conclave/models.py +++ b/src/conclave/models.py @@ -22,7 +22,7 @@ class ModelAnswer(BaseModel): Attributes: name: Friendly council member name (e.g. ``"grok"``). - model_id: Resolved LiteLLM model id (e.g. ``"xai/grok-4.3"``). + model_id: Resolved provider-prefixed model id (e.g. ``"xai/grok-4.3"``). answer: The raw text answer, or ``None`` if the call failed. latency_s: Wall-clock seconds for the call. usage: Token usage if reported by the provider. @@ -73,7 +73,7 @@ class AdversarialResult(BaseModel): judge could not run. verdict_error: Error message if the judge step failed, else ``None``. judge: Friendly name of the judge (synthesizer) model. - judge_model_id: Resolved LiteLLM id of the judge. + judge_model_id: Resolved provider-prefixed id of the judge. """ proposer: str @@ -101,7 +101,7 @@ class CouncilResult(BaseModel): ``debate`` this mirrors the final round so existing consumers that read ``answers``/``synthesis`` keep working unchanged. synthesizer: Friendly name of the synthesizer model, if synthesis ran. - synthesizer_model_id: Resolved LiteLLM id of the synthesizer. + synthesizer_model_id: Resolved provider-prefixed id of the synthesizer. synthesis: The merged consolidated answer, or ``None`` if not produced. For ``debate`` this holds the final synthesized answer; for ``adversarial`` it mirrors the judge's verdict. diff --git a/src/conclave/registry.py b/src/conclave/registry.py index 59d4ddd..0121d2b 100644 --- a/src/conclave/registry.py +++ b/src/conclave/registry.py @@ -2,7 +2,7 @@ This module owns, in ONE place, everything that defines a built-in provider: -* its LiteLLM provider prefix, +* its provider prefix, * the env var(s) that satisfy its key, * (for OpenAI-compatible providers) its full ``/chat/completions`` URL, * the friendly-name -> default model id mapping. @@ -65,7 +65,7 @@ class OpenAICompatProvider: env_vars: tuple[str, ...] -# Friendly name -> default LiteLLM model id. Overridable via ~/.conclave/config.yml. +# Friendly name -> default provider-prefixed model id. Overridable via ~/.conclave/config.yml. DEFAULT_MODELS: dict[str, str] = { "grok": "xai/grok-4.3", "gemini": "gemini/gemini-2.5-pro", @@ -100,7 +100,7 @@ class OpenAICompatProvider: "anthropic": ("ANTHROPIC_API_KEY",), } -# Derived: LiteLLM provider prefix -> the env var(s) that satisfy it. Built from +# Derived: provider prefix -> the env var(s) that satisfy it. Built from # the single-source tables above so it can never drift from them. The first # present var in the list is the active key. Order matters for fallbacks. PROVIDER_ENV_VARS: dict[str, list[str]] = { @@ -165,14 +165,14 @@ def _assert_metadata_consistent() -> None: def provider_prefix(model_id: str) -> str: - """Extract the LiteLLM provider prefix from a model id. + """Extract the provider prefix from a model id. Args: model_id: e.g. ``"xai/grok-4.3"``. Returns: The provider prefix (``"xai"``). If the id has no ``/`` we treat the - whole string as the prefix, which mirrors LiteLLM's bare-name handling. + whole string as the prefix (the bare-name convention for unprefixed ids). """ return model_id.split("/", 1)[0] if "/" in model_id else model_id