Moves JSON parsing inside try/except block to handle API
maintenance pages gracefully. Adds JSONDecodeError handling.
- Add `import json` at top of file
- Move `search_resp.json()` inside try block (line 84)
- Add `except json.JSONDecodeError` handler with warning log
- Return empty list on invalid JSON (graceful degradation)
- Add unit test for maintenance page scenario
Fixes: production crash on PubMed maintenance pages
- Add @pytest.mark.unit markers to all test functions
- Implement test_reporter_ran_tracking_still_works test
- Replace `if False: yield` with cleaner _empty_async_generator helper
- Add _create_task_prompt mock to test_internal_messages_are_filtered
- Use ORCH_MSG_KIND_* constants instead of string literals in _process_event
## Problem
After report synthesis, extra "JUDGING: ManagerAgent" and "PROGRESS: Step 11"
events appeared in the UI, confusing users. Root cause: we were treating
`ExecutorCompletedEvent` as a UI event when it's actually internal framework
bookkeeping (auto-emitted by MS Agent Framework for every executor).
## Solution
1. **Silence ExecutorCompletedEvent**: Remove UI event emission, keep only
internal state tracking (reporter_ran flag)
2. **Add metadata filtering**: Filter out `task_ledger` and `instruction`
messages from AgentRunUpdateEvent stream
3. **Remove dead code**: Delete unused `_handle_completion_event` and
`_get_event_type_for_agent` methods
## Changes
- src/orchestrators/advanced.py: Silence completion events, add metadata filter
- tests/unit/test_orchestrator_noise.py: New regression tests
- tests/unit/orchestrators/test_accumulator_pattern.py: Update expectations
- docs/bugs/P2_EXECUTOR_COMPLETED_EVENT_UI_NOISE.md: Full bug documentation
## Validation
- Senior …
* fix(deps): Upgrade agent-framework-core to 1.0.0b251204 (SPEC-18)
Breaking API changes in upstream require event class migration:
- MagenticAgentDeltaEvent → AgentRunUpdateEvent
- MagenticAgentMessageEvent → ExecutorCompletedEvent
- MagenticFinalResultEvent → (removed, use WorkflowOutputEvent)
Upstream fixed the repr bug we worked around in SPEC-17.
Keep Accumulator Pattern as safety net for now.
Closes P0: HuggingFace Spaces deployment blocked
* docs: Add SPEC-18 documentation and fix test docstring
- Add docs/specs/SPEC_18_AGENT_FRAMEWORK_UPGRADE.md with full migration guide
- Update test_accumulator_pattern.py docstring to reference new event classes
Part of SPEC-18: Agent Framework Core Upgrade
* refactor: Address CodeRabbit review feedback
- Use defensive getattr for event.data.text (consistency)
- Remove redundant isinstance check in _handle_final_event
- Update sync dates in requirements.txt and workflow-diagrams.md
- Add language specifier to SPEC-18 code block
Note:…
Critical fixes:
- HuggingFaceProvider now requires HF_TOKEN (raises clear RuntimeError if missing)
- Fixed test claiming "no keys" but setting hf_token
Minor fixes:
- service_loader.py: sk-ant- keys now properly excluded from OpenAI path
- llamaindex_rag.py: Added defense-in-depth key prefix validation
- Removed all Anthropic mentions from user-facing messages (4 places)
fix(arch): End-to-end BYOK support for unified architecture
This commit completes BYOK (Bring Your Own Key) propagation through the
ENTIRE architecture - from UI to LLM clients AND embedding services.
## Changes
### LLM Layer (Chat/Agents)
- `get_model(api_key=None)` - PydanticAI model factory now accepts BYOK
- `get_chat_client(api_key=None)` - Already fixed in prior commit
- All `create_*_agent(api_key=None)` functions updated
- `JudgeHandler`, `LLMSubIterationJudge` accept api_key
### Embedding Layer (RAG/Memory)
- `LlamaIndexRAGService(api_key=None)` - Prioritizes BYOK over env
- `get_embedding_service(api_key=None)` - Activates premium tier on BYOK
- `get_embedding_service_if_available(api_key=None)` - Same
### Orchestrators (Plumbing)
- `AdvancedOrchestrator` - Captures _api_key, passes to both chat client AND embeddings
- `HierarchicalOrchestrator` - Same pattern
- `LangGraphOrchestrator` - Patched (deprecated but won't crash)
- `orchestrators/factory.py` - Passes api_key to all orchestrators
### Cleanup
- Removed dead Anthropic cod…
fix(P0): Auto-detect OpenAI provider from BYOK api_key prefix
Claude
Unverified signature
e4c6475
Bug: When users entered an OpenAI key (sk-...) in Gradio without
a provider parameter, the client factory only checked settings.has_openai_key
(env var) and fell through to HuggingFace, causing V1 chat completion errors.
Fix: Add provider auto-detection from api_key prefix in get_chat_client():
- sk-ant-... → Anthropic (NotImplementedError - not yet supported)
- sk-... → OpenAI (now correctly routed)
- hf_... → Falls through to HuggingFace (default)
Order matters: "sk-ant-" must be checked before "sk-" since both share prefix.
Tests added:
- test_byok_auto_detects_openai_from_key_prefix (the critical fix test)
- test_byok_auto_detects_anthropic_from_key_prefix
- test_byok_hf_token_falls_through_to_huggingface
- test_anthropic_provider_raises_not_implemented
All 310 unit tests pass.
fix(P0): Implement Accumulator Pattern to resolve Repr Bug (#117)
The _convert_messages() method now accesses msg.contents to extract
tool_calls and tool_call_id for proper conversation history serialization.
Update test mocks to include contents=None to match the expected interface.
* chore: Update dependencies and verify SPEC-16 for Unified Chat Client
* feat: Implement unified ChatClient architecture (SPEC-16) Phase 1
* refactor: Deprecate Simple Mode and map to Unified Advanced Mode (SPEC-16 Phase 2)
* refactor: Complete SPEC-16 cleanup - remove stale dual-mode tests
- Delete obsolete e2e/integration tests referencing removed functions
(check_magentic_requirements, mode="simple", etc.)
- Update unit tests for unified architecture (no mode parameter)
- Fix type errors in HuggingFaceChatClient (add type: ignore for untyped base)
- Remove mode toggle from Gradio UI
- Add ChatClient factory tests
Closes #105, Fixes #113
Refs #114 (tech debt: naming cleanup deferred)
* chore: Sync pre-commit mypy with project dependencies
Add agent-framework-core to pre-commit additional_dependencies so
mypy runs with the same type information in pre-commit hooks as in
`make typecheck`.
Previously, the pre-commit mypy hook ran in isolation without
agent_framework types, ca…
fix(tests): Correct test assertions for CI/CD environment
Claude
Unverified signature
b93f9a0
- test_termination_on_timeout: Accept "timeout_synthesis_failed" reason
since unit tests run without API keys, causing synthesis to fail
- test_graph_execution_flow: Mock get_model() to return "test" provider
since pydantic-ai needs a valid model string during Agent init
Both fixes address test failures in environments without LLM API keys.
- Extract magic number 45 to class constant _EST_SECONDS_PER_ROUND (advanced.py)
- Add @pytest.mark.unit to test_advanced_p2_dead_zones.py
- Remove debug print statements from test
- Add pytestmark = pytest.mark.unit to test_magentic_judge_termination.py
- Fix import ordering (stdlib before third-party)
- Add fallback p=0.15 for progress events without iteration (app.py)
- Refactor max_iters lookup with getattr chains to reduce statement count
- Fix SPEC_16 markdown: list spacing (1. vs 1. ) and code block languages
All 327 tests pass.
test(agents): verify judge termination prompt for SPEC-15
1. Add @pytest.mark.unit to test class for proper categorization
2. Handle user_task before text extraction (edge case fix)
3. Improve truncation tests to actually detect regression:
- Test sentence boundary truncation with proper position
- Test word boundary fallback separately
4. Remove unused imports
Co-authored-by: CodeRabbit AI <coderabbit@users.noreply.github.com>
Problem: Advanced orchestrator exposed raw internal framework events
from agent-framework-core to users:
- `Manager (task_ledger): We are working to address...` (truncated)
- `Manager (instruction): Conduct targeted searches...` (truncated)
- All mapped to type="judging" regardless of actual purpose
Solution:
1. Filter internal events: `task_ledger` and `instruction` now hidden
2. Transform: `user_task` → type="progress" with friendly message
3. Smart truncation: Cut at sentence/word boundaries, not mid-word
Tests: tests/unit/orchestrators/test_advanced_events.py (4 tests)
Closes #106
- Added a new synthesis method in the JudgeHandler to utilize free HuggingFace Inference for narrative generation in Free Tier mode.
- Updated the Orchestrator to check for the judge's synthesis method, ensuring consistent behavior across judging and synthesis.
- Enhanced integration and unit tests to verify the correct usage of the new synthesis method and fallback mechanisms.
- Documented the bug related to synthesis incorrectly using server-side API keys, outlining the root cause and potential fixes.
This change addresses user confusion and improves the Free Tier experience by ensuring expected functionality without requiring an API key.
fix: P0 provider mismatch and code quality audit fixes (#102)
* feat: add outcome measures to ClinicalTrials.gov tool
- Add OutcomesModule and HasResults to FIELDS constant
- Extract primary outcomes with measure and timeFrame
- Show results availability status with posted date
- Boost relevance for trials with results (0.90 vs 0.85)
- Add 4 unit tests per SPEC_14
Closes #95
* fix: address CodeRabbit review feedback for SPEC_14
- Fix unconditional ellipsis: Only add "..." when summary > 400 chars
- Refine primary outcome truncation: Build full string before truncating
- Extract _extract_primary_outcome() helper to reduce statement count
- Add identificationModule to test mock for completeness
Addresses review comments on PR #100.
* test: add pytest.skip for API flakiness resilience
Add defensive skip if ClinicalTrials.gov API returns no results,
making the integration test more resilient to external API changes.
Addresses CodeRabbit review feedback on PR #100.
* fix(SPEC_11): address CodeRabbit review feedback
- Update run_full.py docstring to reference sexual health pipeline (not drug repurposing)
- Update run_full.py help text to use sexual health query example
- Fix app.py domain display to show "Sexual Health" (not "Sexual_Health")
- Update test_nodes.py mock data to use sexual health terms (Testosterone, Androgen Receptor)
- Add @pytest.mark.unit markers to test_judges.py test classes
- Add specific assertion for next_search_queries in test_judges.py
- Add missing @pytest.mark.asyncio marker to test_mcp_tools.py
- Update test_mcp_tools.py and test_clinicaltrials.py to use sexual health queries
- Fix SPEC_12 markdown bare code fence (MD040)
* fix(SPEC_11): comprehensive domain alignment audit
Second pass of CodeRabbit review fixes - found additional domain mismatches:
- examples/search_demo/run_search.py: Update docstring from "drug repurposing" to "sexual health"
- examples/orchestrator_demo/run_agent.py: Update help text from "metf…
feat(SPEC_11): finalize transition to Sexual Health Research Specialist
This commit completes the transition of DeepBoner to a dedicated Sexual Health Research Agent by removing all references to "general" and "drug repurposing" domains. Key changes include:
- Updated domain defaults to exclusively use "sexual_health".
- Replaced all example queries and documentation to reflect a focus on sexual health topics.
- Removed any lingering references to non-sexual health concepts in code and tests.
- Ensured all tests are aligned with the new domain focus, passing successfully.
This change reinforces the project's identity and simplifies the codebase, enhancing clarity and usability for users focused on sexual health research.
Closes #89.
feat(SPEC_11): narrow scope to sexual health only
BREAKING CHANGE: Remove GENERAL and DRUG_REPURPOSING domains
DeepBoner is now a focused Sexual Health Research Specialist, not a
general-purpose research agent.
Changes:
- Remove ResearchDomain.GENERAL and ResearchDomain.DRUG_REPURPOSING
- Remove GENERAL_CONFIG and DRUG_REPURPOSING_CONFIG from domain.py
- Set DEFAULT_DOMAIN = ResearchDomain.SEXUAL_HEALTH
- Update Gradio examples (remove Metformin/Alzheimer's)
- New example: "Testosterone therapy for hypoactive sexual desire disorder?"
- Hide domain dropdown (only one option now)
- Update all domain-related tests
Closes #89
* feat: implement SPEC_10 domain-agnostic refactor
* fix: complete SPEC_10 audit - license + HierarchicalOrchestrator domain
License Fixes:
- LICENSE: Fix copyright "Antibody Training Pipeline ESM" → "DeepBoner Contributors"
- pyproject.toml: Add missing license = "Apache-2.0" field
- README.md: Fix frontmatter license: mit → apache-2.0
Domain Threading Fixes:
- hierarchical.py: Add domain param to __init__ and pass to ResearchTeam
- factory.py: Pass domain to HierarchicalOrchestrator
All 237 tests pass. Domain now properly threaded through all orchestrators.
* test: enhance domain handling in orchestrators and judges
- Updated unit tests for `configure_orchestrator` to include mock mode and free tier scenarios, ensuring the domain is correctly passed to handlers.
- Refactored tests for `JudgeHandler` to mock model retrieval, allowing for domain acceptance without API key requirements.
- Improved `AdvancedOrchestrator` tests to mock API key validation and ensure domain handling i…
BREAKING: Pre-commit was using ancient tool versions causing divergence:
- ruff: v0.4.4 → v0.14.7 (10 minor versions behind!)
- mypy: v1.10.0 → v1.19.0 (9 minor versions behind!)
This caused CI to fail because ruff formatting behavior changed
significantly between versions. Now pre-commit and CI use same versions.
Also reformatted 2 test files that had version-specific formatting.
- Replaced the mock for the pydantic_ai Agent with a mock for get_model to avoid real API key requirements.
- Enhanced the test by mocking the Agent class entirely to ensure proper behavior during initialization.
- Adjusted the test setup to maintain functionality while improving isolation from external dependencies.
feat: Enhance research workflow with embedding service integration
- Updated graph nodes to accept an optional EmbeddingService for improved evidence handling and deduplication.
- Refactored search, judge, resolve, and synthesize nodes to utilize the embedding service for enhanced functionality.
- Modified the research graph creation to bind the embedding service to worker nodes, ensuring seamless integration.
- Added logging for better traceability during node execution.
- Expanded unit and integration tests to cover new embedding service interactions and ensure robust functionality.
feat: Integrate LangGraph for enhanced research orchestration
- Added LangGraph dependencies to pyproject.toml and uv.lock for improved state management and orchestration capabilities.
- Implemented LangGraph-based orchestrator in src/orchestrators/langgraph_orchestrator.py, enabling structured research workflows.
- Developed graph nodes and state management in src/agents/graph, including search, judge, and synthesis functionalities.
- Updated app.py to support new "god" mode for advanced orchestration.
- Enhanced documentation for active bugs and architectural gaps related to LangGraph integration.
- Added unit and integration tests to ensure functionality and reliability of the new features.
* feat: implement SPEC_06 fixes for simple mode synthesis
Implements research-backed architecture changes for Simple mode:
- Diverse evidence selection with lost-in-the-middle mitigation
- Debiased judge prompt (scoring only, no decision making)
- Code-enforced termination criteria (prevents infinite loops)
- Real partial synthesis with drug candidates when max iterations reached
- Unit and integration tests for all new logic
* fix: address CodeRabbit review feedback
- Fix type annotation: recommendation str -> Literal["continue", "synthesize"]
- Add @pytest.mark.unit markers to unit tests
- Add @pytest.mark.integration markers to integration tests
- Simplify early/late evidence assertions using set intersection
- Replace next() with explicit filtering for clearer test diagnostics
- Extract hardcoded thresholds (50, 30) to TERMINATION_CRITERIA
- Fix e2e mock to accept iteration/max_iterations parameters
All 177 tests pass, mypy clean, ruff clean.
* docs: add P3 architectural gap r…
feat: add service loader + SPEC_06 + P0 bug report
Service Loader:
- Create src/utils/service_loader.py for centralized lazy loading
- All orchestrators now use centralized service loading
- Enforces OrchestratorProtocol on Advanced and Hierarchical
SPEC_06 (Simple Mode Synthesis - not yet implemented):
- Research-backed spec for fixing Simple mode never synthesizing
- Identifies 6 root causes with November 2025 LLM-as-Judge research
- Separates scoring from decision-making (debiased architecture)
P0 Bug Report:
- Documents Simple mode producing only citations (no synthesis)
- Confidence dropping to 0% in late iterations (context overflow)
- Judge never recommending "synthesize" even with 455 sources
CodeRabbit concerns from PR #70 addressed.
refactor: Organize orchestrators into dedicated package
Claude
e82d9c9
- Create src/orchestrators/ package with proper module structure
- base.py: Shared protocols (SearchHandlerProtocol, JudgeHandlerProtocol)
- simple.py: Basic search-judge loop orchestrator (was orchestrator.py)
- advanced.py: Multi-agent MS Agent Framework orchestrator (was orchestrator_magentic.py)
- hierarchical.py: Sub-iteration middleware orchestrator
- factory.py: Factory pattern for orchestrator creation
- __init__.py: Clean public API with facade pattern
Design principles applied:
- Single Responsibility (SRP): Each file has one clear job
- Interface Segregation (ISP): Protocols in base.py
- Factory Pattern (GoF): Centralized creation logic
- Facade Pattern: Clean public imports via __init__.py
All imports updated across:
- src/app.py, src/agents/
- tests/unit/, tests/e2e/, tests/integration/
- examples/orchestrator_demo/
All 147 tests pass, linting and typecheck clean.
fix: implement SPEC_04 (Magentic UX) and SPEC_05 (cleanup)
- Implemented OpenAlexTool in src/tools/openalex.py
- Added comprehensive unit and integration tests in tests/unit/tools/test_openalex.py
- Updated src/tools/__init__.py to export the new tool
- Updated SPEC_03 with final implementation details and test patterns
- Features: Citation count sorting, abstract reconstruction, concept tagging, OA links
- Verified with 100% test pass rate and clean lint/type checks
feat: Implement SPEC_01 (Termination) and SPEC_02 (E2E Tests)
- SPEC_01: Added timeout (300s) and progress events to MagenticOrchestrator
- SPEC_02: Created tests/e2e/ with mocked tests for Simple and Advanced modes
- Docs: Updated specs to match codebase state