Revert PR #14 (Pydantic AI migration) — restore subscription auth, keep index hardening#15
Merged
Merged
Conversation
This reverts PR #14 (merge 5ed0923, mainline -m 1). The Pydantic AI migration moved the daemon's Librarian + Scholar onto pydantic-ai's `anthropic:` provider, which authenticates ONLY via the metered Anthropic API (ANTHROPIC_API_KEY, or Bedrock/Vertex/Foundry) — it cannot use the Claude Code subscription the old claude-agent-sdk path ran on. That silently switched the daemon's billing from flat subscription to pay-per-token, and with no key set the daemon crashes every non-empty Librarian/Scholar run. Subscription auth is a hard requirement, so restore the claude-agent-sdk model layer. The index/pickle hardening (d7f28ec) that rode in on the same PR is unrelated and worth keeping; it is re-applied in the follow-up commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…safe `load_pickled` only caught (OSError, UnpicklingError, EOFError, AttributeError, ModuleNotFoundError), so a corrupt pickle that surfaced as UnicodeDecodeError (a ValueError, not UnpicklingError) propagated instead of degrading to a rebuild. In the daemon this silently disabled embedding retrieval until the index was deleted by hand — priming fell back to BM25-only. Broaden to `except Exception` to honour the documented "any read failure -> rebuild" contract (BaseException still propagates). Root cause of the corruption: save_index wrote a shared `<name>.tmp` before the atomic rename, but the daemon saves from parallel Librarian threads (+ priming + prewarm). Concurrent rebuilds of a stale index interleaved into that one temp file, producing a half-written pickle. Add shared `bm25.save_pickled` that writes a unique temp file per writer (tempfile.mkstemp) then os.replace; route both BM25 and embedding save_index through it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
PR #14 migrated the daemon's Librarian + Scholar to pydantic-ai bound to
anthropic:model strings. pydantic-ai's Anthropic provider authenticates only via the metered API (ANTHROPIC_API_KEY, or Bedrock/Vertex/Foundry clients) — it cannot use the Claude Code subscription the oldclaude-agent-sdkpath ran on. That silently switched the daemon's billing from flat subscription to pay-per-token, and with no key set the daemon crashes on every non-empty Librarian/Scholar run (UserError: Set the ANTHROPIC_API_KEY...). Subscription auth is a hard requirement.CI didn't catch this because model calls are mocked in tests — a billing-model swap is invisible to ruff/pyright/pytest.
What
5ed0923, mainline-m 1) → restores theclaude-agent-sdkmodel layer (subscription auth),_response_parser,llm.py, and the old Scholar/Librarian path.d7f28ec) that rode in on feat(scholar): migrate curator to Pydantic AI with typed structured output #14 —load_pickledself-heal + concurrency-safesave_pickled. Genuine fix, worth keeping.Verification
daemon/is byte-identical to pre-migration238e7a0(git diff 238e7a0 HEAD -- daemon/is empty).tools/search/is identical to currentmain(pickle fix preserved).claude-agent-sdkrestored;pydantic-airemoved from daemon deps;uv.lockreverted to match.Note — the pydantic-ai work isn't lost
It remains in history and on the
feat/scholar-pydantic-aibranch. If we want its typed-output / no-json-repair benefits later, the path that preserves subscription billing is: keepclaude-agent-sdkfor the model call and layer Pydantic validation on its tool-use — no framework swap, no billing change.🤖 Generated with Claude Code