feat(v3.0): wire API-based summarizer from config#26
Closed
RichardHightower wants to merge 2 commits into
Closed
Conversation
- Read provider/model/api_key_env from SummarizerSettings config - Construct ApiSummarizer (OpenAI or Anthropic) when API key available - Fallback to MockSummarizer with warning when no API key found - Add build_summarizer() function for testable summarizer construction - Add unit tests for provider selection and env var lookup - Update planning docs for v3.0
Contributor
Author
|
Closing in favor of #27, which carries the same feature plus the review feedback applied:
The ROADMAP/STATE edits from this PR are reverted in #27 because they collide with the unpushed local v3.0 plan (Phase 51 = Retrieval Orchestrator, not Summarizer Wiring). The summarizer wiring will get its own slot in v3.0 via a follow-up (likely Phase 54). |
RichardHightower
added a commit
that referenced
this pull request
Apr 28, 2026
* feat(v3.0): wire API-based summarizer from config - Read provider/model/api_key_env from SummarizerSettings config - Construct ApiSummarizer (OpenAI or Anthropic) when API key available - Fallback to MockSummarizer with warning when no API key found - Add build_summarizer() function for testable summarizer construction - Add unit tests for provider selection and env var lookup - Update planning docs for v3.0 * fix(docs): use full path for Summarizer doc link in commands.rs * revert(planning): drop ROADMAP/STATE edits from PR #26 PR #26 added a "v3.0 — Real Summarization" section to ROADMAP.md and a v3.0 in-progress block to STATE.md, both numbering this work as Phase 51. The local main branch (not yet on origin/main) already has "v3.0 Competitive Parity & Benchmarks" with Phase 51 = Retrieval Orchestrator, Phase 52 = Simple CLI API, Phase 53 = Benchmark Suite. Carrying PR #26's planning edits forward would create a phase-numbering collision when local main is pushed. Slot the summarizer wiring into the existing v3.0 plan in a follow-up (likely a new Phase 54 "Real Summarization", or fold into Phase 51's LLM reranker work). * refactor(summarizer): apply PR #26 review feedback Addresses code-review findings on PR #26 (closing #26 in favor of this PR). All four pr-precheck gates pass: fmt, clippy --all-targets --all-features -D warnings, full workspace test (~825 tests), doc with RUSTDOCFLAGS=-D warnings. Decision logic split (functional core / imperative shell): - Extract pure pick_summarizer_kind(settings, key_available) -> SummarizerKind so tests assert on the branch taken instead of only verifying non-panic. Five of seven original tests ended with `let _ = summarizer;` which couldn't detect a regression that, e.g., always returned Mock. API hygiene: - Drop dead 2-tuple from resolve_api_key. The second element was always discarded by the only caller and misleadingly returned the *default* env var name even when api_key_env override was active, so any future caller using it would log the wrong var on a cache miss. - Downgrade pub -> pub(crate) on build_summarizer, env_var_for_provider, and pick_summarizer_kind. memory-daemon has both lib.rs and a [[bin]] target, so pub leaked test helpers as part of the library's public API. Helpers + duplication: - Extract is_anthropic / is_openai / default_env_var_for_provider using eq_ignore_ascii_case (was: 3 sites of `.to_lowercase() == "anthropic"` with per-call allocations). - Warn on unknown providers before fail-open to OpenAI (was: silent fall-through that would have routed an OPENAI_API_KEY to api.openai.com for typos like "openi" or genuinely different providers like "google"). Tests (7 weak -> 16 strong): - 4 env_var_for_provider mapping tests (kept as-is) - 6 pick_summarizer_kind decision tests (NEW: assert exact SummarizerKind for openai / anthropic / mixed-case / unknown-provider / no-key paths) - 5 resolve_api_key tests (NEW: regression guard for the precedence ordering api_key > api_key_env > provider default; explicit override vs custom env var; missing custom env var) - 1 build_summarizer smoke test (verifies wiring + Arc allocation) Closes #26 * fix(retrieval): satisfy clippy::unnecessary_sort_by (Rust 1.95+) CI runs `dtolnay/rust-toolchain@stable` which now ships clippy from Rust 1.95, where `clippy::unnecessary_sort_by` is enforced under `-D warnings`. The pre-existing `sort_by(|a, b| b.1.cmp(&a.1))` on stale_filter.rs:163 fires the lint and blocks CI for any branch. Replace with the canonical `sort_by_key(|b| Reverse(b.1))` form suggested by clippy. Semantically equivalent (descending order by .1). Local toolchain (1.93) does not have this lint yet, which is why this slipped through `task pr-precheck` here. Fixed in this PR to unblock CI; benefits #25 and any other open branch. * fix(workspace): fix remaining clippy::unnecessary_sort_by sites Round 2 of the Rust 1.95 stable upgrade adaptation. Previous commit fixed stale_filter.rs:163 which let CI advance past memory-retrieval, where it then surfaced the same lint in three more sites. Workspace grep for the simple `cmp(&)` form (which the lint flags) covers all remaining cases: - memory-storage/src/db.rs:462 (sort_by_key on start_time, ascending) - memory-storage/src/db.rs:481 (same in get_child_nodes) - memory-service/src/agents.rs:85 (Reverse for descending last_seen_ms) - memory-toc/src/summarizer/mock.rs:122 (Reverse for descending count) The remaining sort_by sites in the workspace use multi-line closures or partial_cmp (Option-returning) which the lint cannot auto-simplify; they pass clippy as-is. All semantically equivalent. Tests on the three modified crates remain green (110 + 42 + 70 + doctests).
RichardHightower
added a commit
that referenced
this pull request
Apr 28, 2026
…al phase stack Sync planning files with origin/main reality after PR #27 merged as `3a73582`: - ROADMAP.md: insert Phase 51.5 (API Summarizer Wiring) between Phases 51 and 52 as a decimal out-of-band phase. Marks complete (merged 2026-04-28). - STATE.md: bump status to in_progress, total_phases 3 -> 4, completed 0 -> 1. Add Out-of-band Work section flagging: - PR #25 (cross-project memory) phase-numbering conflict with local Phase 51 - Local-only gsd/phase-{51..58} stack (~80 commits, no PRs yet) Phase 51.5 supersedes closed PR #26 with stronger tests (16 vs 7) and a pick_summarizer_kind decision split. Inserted out-of-band because the summarizer wiring shipped before Phase 51 (Retrieval Orchestrator) itself. No code changes. pr-precheck (fmt + clippy + test + doc) passes. Co-Authored-By: Claude Opus 4.7 (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.
Summary
Wires the existing
ApiSummarizer(OpenAI + Anthropic) into the daemon from config and environment variables. Previously hardcoded toMockSummarizerwith a TODO comment.What changed
crates/memory-daemon/src/commands.rsbuild_summarizer()function: reads provider/model from config, resolves API key from env var or config, constructsApiSummarizeror falls back toMockSummarizerwith warning. 7 unit tests.crates/memory-types/src/config.rsapi_key_env: Option<String>toSummarizerSettingsfor custom env var override (serde(default)for backward compat).planning/STATE.md,.planning/ROADMAP.mdHow it works
Set the corresponding env var (
OPENAI_API_KEYorANTHROPIC_API_KEY) and the daemon picks it up automatically. Without an API key, it falls back to MockSummarizer with a warning log.Design decisions
api_key_env.Option<String>withserde(default), existing configs unchanged.OpenAI,openai,OPENAIall work.Tests
7 unit tests covering: