Diomedes Git
commited on
Commit
·
a041674
1
Parent(s):
0b15c28
server, adding some basic. also got rid of gemini mess, and deleted reviews and moved notes out of repo
Browse files- notes_etc/development_guide_01.md +0 -797
- notes_etc/development_guide_02.txt +0 -181
- notes_etc/exposing_cluas_as_an_MCP.py +0 -14
- notes_etc/possible_architecture_diagram.txt +0 -48
- notes_etc/possible_project_structure.txt +0 -32
- pyproject.toml +1 -0
- reviews/changes.md +0 -220
- reviews/code_review_2025-11-15_14-30-00.md +0 -70
- reviews/code_review_2025-11-15_15-00-00.md +0 -62
- reviews/code_review_2025-11-15_15-30-00.md +0 -62
- reviews/code_review_2025-11-15_16-00-00.md +0 -37
- reviews/code_review_2025-11-18_10-00-00.md +0 -61
- reviews/code_review_2025-11-18_10-30-00.md +0 -50
- reviews/code_review_2025-11-18_16-00-00.md +0 -42
- reviews/code_review_2025-11-18_17-00-00.md +0 -52
- reviews/code_review_2025-11-18_18-00-00.md +0 -55
- reviews/code_review_2025-11-18_19-00-00.md +0 -54
- reviews/code_review_2025-11-18_20-00-00.md +0 -47
- src/characters/corvus.py +0 -100
- src/cluas_mcp/server.py +17 -1
- src/orchestrator.py +0 -45
- uv.lock +340 -3
notes_etc/development_guide_01.md
DELETED
|
@@ -1,797 +0,0 @@
|
|
| 1 |
-
# Corvid Council - Development Guide
|
| 2 |
-
|
| 3 |
-
## Project Overview
|
| 4 |
-
|
| 5 |
-
**Name**: Corvid Council
|
| 6 |
-
**Hackathon**: Gradio Agents & MCP Hackathon - Winter 25
|
| 7 |
-
**Track**: Building MCP (Creative)
|
| 8 |
-
**Tags**: `building-mcp-track-creative`
|
| 9 |
-
|
| 10 |
-
### Concept
|
| 11 |
-
A multi-agent group chat where 4 AI crow experts discuss topics, each using specialized MCP tools. The Gradio app itself also exposes MCP tools, allowing external applications to query the expert panel.
|
| 12 |
-
|
| 13 |
-
### The Hook
|
| 14 |
-
"What if you could consult a panel of AI experts? Use it two ways: watch them research and debate in a group chat, or query them as an MCP tool from Claude Desktop or any MCP client."
|
| 15 |
-
|
| 16 |
-
---
|
| 17 |
-
|
| 18 |
-
## Architecture
|
| 19 |
-
|
| 20 |
-
```
|
| 21 |
-
External User/App (Claude Desktop, etc.)
|
| 22 |
-
↓ (calls MCP tool)
|
| 23 |
-
ask_crow_council(question)
|
| 24 |
-
↓ (hits)
|
| 25 |
-
Gradio App (IS an MCP server)
|
| 26 |
-
↓ (internally orchestrates)
|
| 27 |
-
CouncilOrchestrator
|
| 28 |
-
↓ (manages)
|
| 29 |
-
4 Character Agents (Corvus, Magpie, Raven, Crow)
|
| 30 |
-
↓ (each uses)
|
| 31 |
-
Character-Specific MCP Tools (~12-15 total)
|
| 32 |
-
↓ (which call)
|
| 33 |
-
External APIs (Semantic Scholar, eBird, Weather, etc.)
|
| 34 |
-
↓ (returns aggregated response)
|
| 35 |
-
Back to User
|
| 36 |
-
```
|
| 37 |
-
|
| 38 |
-
### Two Interfaces, Same Backend
|
| 39 |
-
|
| 40 |
-
**Interface 1: Gradio Chat UI** (Direct access)
|
| 41 |
-
- Users see the full group chat
|
| 42 |
-
- Watch characters use their tools in real-time
|
| 43 |
-
- See sources, debates, synthesis
|
| 44 |
-
- Can inject questions
|
| 45 |
-
|
| 46 |
-
**Interface 2: MCP Tools** (Programmatic access)
|
| 47 |
-
- External apps call `ask_crow_council(question)`
|
| 48 |
-
- Same orchestration happens internally
|
| 49 |
-
- Returns structured, synthesized response
|
| 50 |
-
- Fast, clean API integration
|
| 51 |
-
|
| 52 |
-
---
|
| 53 |
-
|
| 54 |
-
## The Characters
|
| 55 |
-
|
| 56 |
-
### Corvus (The Scholar) - Melancholic
|
| 57 |
-
**Archetype**: Academic, thorough, perfectionist
|
| 58 |
-
**Personality**:
|
| 59 |
-
- PhD researcher studying corvid cognition
|
| 60 |
-
- Every claim needs citation
|
| 61 |
-
- Cautious, analytical, sometimes pedantic
|
| 62 |
-
- Posts rarely but substantively
|
| 63 |
-
- Always verifies before sharing
|
| 64 |
-
|
| 65 |
-
**Communication Style**:
|
| 66 |
-
- Long, structured messages
|
| 67 |
-
- Includes citations and methodology
|
| 68 |
-
- Questions assumptions
|
| 69 |
-
- "According to X study (DOI)..."
|
| 70 |
-
|
| 71 |
-
**MCP Tools** (4 tools):
|
| 72 |
-
- `search_corvid_papers(query, years, min_citations)` - Academic database search
|
| 73 |
-
- `get_paper_details(doi)` - Full paper information
|
| 74 |
-
- `verify_claim_against_literature(claim, context)` - Fact-checking
|
| 75 |
-
- `get_citation_network(doi, depth)` - Related research
|
| 76 |
-
|
| 77 |
-
**Behavior Pattern**:
|
| 78 |
-
1. Sees topic → searches papers
|
| 79 |
-
2. Reads abstract/methods → verifies quality
|
| 80 |
-
3. Composes careful response with citations
|
| 81 |
-
4. If others make claims → verifies against literature
|
| 82 |
-
|
| 83 |
-
---
|
| 84 |
-
|
| 85 |
-
### Magpie (The Enthusiast) - Sanguine
|
| 86 |
-
**Archetype**: Social, optimistic, storyteller
|
| 87 |
-
**Personality**:
|
| 88 |
-
- Collects crow stories like magpies collect shiny things
|
| 89 |
-
- Loves viral videos, human-interest pieces
|
| 90 |
-
- Shares everything excitedly, often unchecked
|
| 91 |
-
- Makes connections between unrelated things
|
| 92 |
-
- High energy, frequent poster
|
| 93 |
-
|
| 94 |
-
**Communication Style**:
|
| 95 |
-
- Rapid-fire short messages
|
| 96 |
-
- Uses emojis
|
| 97 |
-
- "omg you HAVE to see this!"
|
| 98 |
-
- Shares first, verifies later (or never)
|
| 99 |
-
|
| 100 |
-
**MCP Tools** (3 tools):
|
| 101 |
-
- `search_social_media(query, platform, timeframe)` - TikTok, Twitter, Reddit
|
| 102 |
-
- `search_web(query)` - General web search
|
| 103 |
-
- `find_trending_content(topic)` - What's viral right now
|
| 104 |
-
|
| 105 |
-
**Behavior Pattern**:
|
| 106 |
-
1. Sees topic → searches social/web immediately
|
| 107 |
-
2. Shares whatever looks interesting
|
| 108 |
-
3. Sometimes posts old/duplicate content
|
| 109 |
-
4. Creates energy, others moderate
|
| 110 |
-
|
| 111 |
-
**Quirk**: Posts old news 30-40% of the time (doesn't check dates)
|
| 112 |
-
|
| 113 |
-
---
|
| 114 |
-
|
| 115 |
-
### Raven (The Activist) - Choleric
|
| 116 |
-
**Archetype**: Action-oriented, passionate, confrontational
|
| 117 |
-
**Personality**:
|
| 118 |
-
- Environmental activist
|
| 119 |
-
- Sees crows as ecosystem health indicators
|
| 120 |
-
- Aggressive fact-gathering
|
| 121 |
-
- Calls out misinformation
|
| 122 |
-
- Posts urgent updates
|
| 123 |
-
|
| 124 |
-
**Communication Style**:
|
| 125 |
-
- Short, urgent messages
|
| 126 |
-
- Exclamation points
|
| 127 |
-
- "We need to act NOW"
|
| 128 |
-
- Challenges others directly
|
| 129 |
-
- Facts as weapons
|
| 130 |
-
|
| 131 |
-
**MCP Tools** (4 tools):
|
| 132 |
-
- `get_environmental_data(location, metric)` - Pollution, habitat data
|
| 133 |
-
- `search_news(query, recency)` - Current news monitoring
|
| 134 |
-
- `fact_check_claim(claim, source)` - Debunking tool
|
| 135 |
-
- `analyze_sentiment(topic, source)` - What are people saying?
|
| 136 |
-
|
| 137 |
-
**Behavior Pattern**:
|
| 138 |
-
1. Sees topic → looks for environmental angle
|
| 139 |
-
2. Searches news for threats/problems
|
| 140 |
-
3. Fact-checks others' claims aggressively
|
| 141 |
-
4. Rallies for action
|
| 142 |
-
|
| 143 |
-
**Creates drama**: Often disagrees with Corvus (action vs. more research)
|
| 144 |
-
|
| 145 |
-
---
|
| 146 |
-
|
| 147 |
-
### Crow (The Observer) - Phlegmatic
|
| 148 |
-
**Archetype**: Calm, patient, contemplative
|
| 149 |
-
**Personality**:
|
| 150 |
-
- Birdwatcher who observes local populations
|
| 151 |
-
- Philosophical, sees long-term patterns
|
| 152 |
-
- Rarely posts but reads everything
|
| 153 |
-
- When speaks, it's meaningful
|
| 154 |
-
- Patience over urgency
|
| 155 |
-
|
| 156 |
-
**Communication Style**:
|
| 157 |
-
- Rare, brief, profound
|
| 158 |
-
- Long silences then sudden insight
|
| 159 |
-
- "I've been watching..."
|
| 160 |
-
- Ties everything together
|
| 161 |
-
- No wasted words
|
| 162 |
-
|
| 163 |
-
**MCP Tools** (3 tools):
|
| 164 |
-
- `get_bird_sightings(location, species, timeframe)` - eBird data
|
| 165 |
-
- `get_weather_patterns(location, duration)` - Weather effects on behavior
|
| 166 |
-
- `analyze_temporal_patterns(data, timeframe)` - Long-term trends
|
| 167 |
-
|
| 168 |
-
**Behavior Pattern**:
|
| 169 |
-
1. Observes conversation quietly
|
| 170 |
-
2. Uses tools to gather observational data
|
| 171 |
-
3. Waits for pattern to emerge
|
| 172 |
-
4. Posts when has something meaningful
|
| 173 |
-
5. Often provides perspective that settles debates
|
| 174 |
-
|
| 175 |
-
**Special role**: The "wise elder" who cuts through noise
|
| 176 |
-
|
| 177 |
-
---
|
| 178 |
-
|
| 179 |
-
## MCP Tool Architecture
|
| 180 |
-
|
| 181 |
-
### Internal MCP Tools (Consumed by App)
|
| 182 |
-
|
| 183 |
-
All tools live in one MCP server: `crow-chat-mcp`
|
| 184 |
-
|
| 185 |
-
**Tool Categories**:
|
| 186 |
-
1. Academic (Corvus): 4 tools
|
| 187 |
-
2. Social/Web (Magpie): 3 tools
|
| 188 |
-
3. Real-time Data (Raven): 4 tools
|
| 189 |
-
4. Observational (Crow): 3 tools
|
| 190 |
-
|
| 191 |
-
**Total**: ~14 core tools
|
| 192 |
-
|
| 193 |
-
**Tool Definition Pattern**:
|
| 194 |
-
```python
|
| 195 |
-
@mcp.tool()
|
| 196 |
-
async def tool_name(
|
| 197 |
-
param1: str,
|
| 198 |
-
param2: int = default_value
|
| 199 |
-
) -> ReturnType:
|
| 200 |
-
"""
|
| 201 |
-
Clear description of what tool does.
|
| 202 |
-
|
| 203 |
-
Args:
|
| 204 |
-
param1: Description
|
| 205 |
-
param2: Description
|
| 206 |
-
|
| 207 |
-
Returns:
|
| 208 |
-
Description of return value
|
| 209 |
-
"""
|
| 210 |
-
# Implementation
|
| 211 |
-
pass
|
| 212 |
-
```
|
| 213 |
-
|
| 214 |
-
### External MCP Tools (Exposed by App)
|
| 215 |
-
|
| 216 |
-
**The Gradio app exposes these tools**:
|
| 217 |
-
|
| 218 |
-
```python
|
| 219 |
-
@mcp.tool()
|
| 220 |
-
async def ask_crow_council(question: str) -> dict:
|
| 221 |
-
"""
|
| 222 |
-
Consult the Corvid Council expert panel.
|
| 223 |
-
|
| 224 |
-
All four experts research using their specialized tools
|
| 225 |
-
and provide a synthesized answer with sources.
|
| 226 |
-
|
| 227 |
-
Returns:
|
| 228 |
-
{
|
| 229 |
-
"consensus": str, # Synthesized answer
|
| 230 |
-
"expert_opinions": [...], # Individual takes
|
| 231 |
-
"sources": [...], # All citations/links
|
| 232 |
-
"confidence": float # 0-1
|
| 233 |
-
}
|
| 234 |
-
"""
|
| 235 |
-
|
| 236 |
-
@mcp.tool()
|
| 237 |
-
async def ask_specific_expert(
|
| 238 |
-
question: str,
|
| 239 |
-
expert: Literal["corvus", "magpie", "raven", "crow"]
|
| 240 |
-
) -> dict:
|
| 241 |
-
"""
|
| 242 |
-
Query one specific expert.
|
| 243 |
-
"""
|
| 244 |
-
|
| 245 |
-
@mcp.tool()
|
| 246 |
-
async def fact_check_claim(claim: str) -> dict:
|
| 247 |
-
"""
|
| 248 |
-
Have the council verify a claim about crows.
|
| 249 |
-
|
| 250 |
-
Returns:
|
| 251 |
-
{
|
| 252 |
-
"verdict": "verified" | "disputed" | "unknown",
|
| 253 |
-
"evidence": [...],
|
| 254 |
-
"expert_consensus": str
|
| 255 |
-
}
|
| 256 |
-
"""
|
| 257 |
-
```
|
| 258 |
-
|
| 259 |
-
---
|
| 260 |
-
|
| 261 |
-
## Core Components
|
| 262 |
-
|
| 263 |
-
### 1. CouncilOrchestrator
|
| 264 |
-
**Purpose**: Coordinates character responses, manages conversation flow
|
| 265 |
-
|
| 266 |
-
**Key Methods**:
|
| 267 |
-
```python
|
| 268 |
-
class CouncilOrchestrator:
|
| 269 |
-
async def process_query(question: str) -> CouncilResult:
|
| 270 |
-
"""Main entry point for both UI and MCP"""
|
| 271 |
-
|
| 272 |
-
async def facilitate_discussion(question, initial_responses) -> Discussion:
|
| 273 |
-
"""Characters respond to each other"""
|
| 274 |
-
|
| 275 |
-
async def synthesize_consensus(responses) -> str:
|
| 276 |
-
"""Create unified answer for MCP calls"""
|
| 277 |
-
```
|
| 278 |
-
|
| 279 |
-
### 2. Character (Base Class)
|
| 280 |
-
**Purpose**: Encapsulates character behavior
|
| 281 |
-
|
| 282 |
-
**Key Methods**:
|
| 283 |
-
```python
|
| 284 |
-
class Character:
|
| 285 |
-
async def research_and_respond(question: str, context: list) -> Response:
|
| 286 |
-
"""Use tools to research, generate response"""
|
| 287 |
-
|
| 288 |
-
async def use_tools(question: str) -> list[ToolResult]:
|
| 289 |
-
"""Call relevant MCP tools"""
|
| 290 |
-
|
| 291 |
-
async def generate_message(question, tool_results, context) -> str:
|
| 292 |
-
"""Compose message in character voice"""
|
| 293 |
-
```
|
| 294 |
-
|
| 295 |
-
### 3. MCPToolManager
|
| 296 |
-
**Purpose**: Handles all MCP tool calls, error handling, rate limiting
|
| 297 |
-
|
| 298 |
-
**Key Methods**:
|
| 299 |
-
```python
|
| 300 |
-
class MCPToolManager:
|
| 301 |
-
async def call_tool(tool_name: str, params: dict) -> ToolResult:
|
| 302 |
-
"""Execute tool with error handling"""
|
| 303 |
-
|
| 304 |
-
async def batch_call_tools(calls: list) -> list[ToolResult]:
|
| 305 |
-
"""Call multiple tools efficiently"""
|
| 306 |
-
```
|
| 307 |
-
|
| 308 |
-
### 4. GradioInterface
|
| 309 |
-
**Purpose**: Chat UI for direct human interaction
|
| 310 |
-
|
| 311 |
-
**Key Methods**:
|
| 312 |
-
```python
|
| 313 |
-
def create_interface() -> gr.Blocks:
|
| 314 |
-
"""Build Gradio chat interface"""
|
| 315 |
-
|
| 316 |
-
async def handle_user_message(message, history, state):
|
| 317 |
-
"""Process user input, orchestrate responses"""
|
| 318 |
-
|
| 319 |
-
def display_tool_usage(character, tool_name):
|
| 320 |
-
"""Show 'Character is using tool...' indicators"""
|
| 321 |
-
```
|
| 322 |
-
|
| 323 |
-
---
|
| 324 |
-
|
| 325 |
-
## Development Phases
|
| 326 |
-
|
| 327 |
-
### Week 1: Core System (Days 1-7)
|
| 328 |
-
|
| 329 |
-
#### Days 1-2: Foundation
|
| 330 |
-
**Goal**: One character working with tools in Gradio
|
| 331 |
-
|
| 332 |
-
- [ ] Set up project structure
|
| 333 |
-
- [ ] Build `CouncilOrchestrator` skeleton
|
| 334 |
-
- [ ] Implement `Character` base class
|
| 335 |
-
- [ ] Create Corvus with 2 tools (search_papers, get_details)
|
| 336 |
-
- [ ] Basic Gradio interface
|
| 337 |
-
- [ ] Test: Corvus responds to question using tools
|
| 338 |
-
|
| 339 |
-
**Success Metric**: Ask "Are crows smart?", see Corvus search papers and respond with citation
|
| 340 |
-
|
| 341 |
-
#### Days 3-4: Second Character
|
| 342 |
-
**Goal**: Two characters interacting
|
| 343 |
-
|
| 344 |
-
- [ ] Add Magpie with 2 tools (search_web, search_social)
|
| 345 |
-
- [ ] Implement character interaction (they respond to each other)
|
| 346 |
-
- [ ] Staggered response timing (2-3 sec apart)
|
| 347 |
-
- [ ] Test: Both characters respond differently to same question
|
| 348 |
-
|
| 349 |
-
**Success Metric**: Two distinct personalities with different tool usage patterns visible
|
| 350 |
-
|
| 351 |
-
#### Days 5-6: Third & Fourth Characters
|
| 352 |
-
**Goal**: Full council assembled
|
| 353 |
-
|
| 354 |
-
- [ ] Add Raven with 2 tools (get_environmental_data, search_news)
|
| 355 |
-
- [ ] Add Crow with 2 tools (get_sightings, get_weather)
|
| 356 |
-
- [ ] Four-way interaction patterns
|
| 357 |
-
- [ ] Test: All four respond to question, some interact with each other
|
| 358 |
-
|
| 359 |
-
**Success Metric**: Rich multi-agent discussion with varied tool usage
|
| 360 |
-
|
| 361 |
-
#### Day 7: Week 1 Polish
|
| 362 |
-
- [ ] Improve system prompts for distinct personalities
|
| 363 |
-
- [ ] Add typing indicators
|
| 364 |
-
- [ ] Better error handling for tool failures
|
| 365 |
-
- [ ] Test conversation flows
|
| 366 |
-
- [ ] Fix bugs
|
| 367 |
-
|
| 368 |
-
---
|
| 369 |
-
|
| 370 |
-
### Week 2: External MCP & Polish (Days 8-14)
|
| 371 |
-
|
| 372 |
-
#### Days 8-9: MCP Exposure
|
| 373 |
-
**Goal**: Gradio app as MCP server
|
| 374 |
-
|
| 375 |
-
- [ ] Implement external MCP tool exposure
|
| 376 |
-
- [ ] `ask_crow_council()` tool
|
| 377 |
-
- [ ] `ask_specific_expert()` tool
|
| 378 |
-
- [ ] Test from Claude Desktop or MCP inspector
|
| 379 |
-
- [ ] Ensure both interfaces use same orchestrator
|
| 380 |
-
|
| 381 |
-
**Success Metric**: External tool call triggers internal discussion, returns synthesized response
|
| 382 |
-
|
| 383 |
-
#### Days 10-11: Additional Tools & Refinement
|
| 384 |
-
**Goal**: Complete tool sets
|
| 385 |
-
|
| 386 |
-
- [ ] Add remaining tools (3rd-4th tool per character)
|
| 387 |
-
- [ ] Implement `fact_check_claim()` external tool
|
| 388 |
-
- [ ] Add tool chaining where appropriate
|
| 389 |
-
- [ ] Better synthesis algorithm for consensus
|
| 390 |
-
- [ ] Rate limiting and caching
|
| 391 |
-
|
| 392 |
-
#### Days 12-13: Polish & Demo Prep
|
| 393 |
-
**Goal**: Production ready
|
| 394 |
-
|
| 395 |
-
- [ ] UI improvements (avatars, timestamps, theming)
|
| 396 |
-
- [ ] Tool usage visualization
|
| 397 |
-
- [ ] Demo mode with curated scenarios
|
| 398 |
-
- [ ] Write comprehensive README
|
| 399 |
-
- [ ] Create demo video showing both interfaces
|
| 400 |
-
- [ ] Test edge cases
|
| 401 |
-
|
| 402 |
-
#### Day 14: Deployment & Documentation
|
| 403 |
-
**Goal**: Ship it
|
| 404 |
-
|
| 405 |
-
- [ ] Deploy to Hugging Face Spaces
|
| 406 |
-
- [ ] Verify both interfaces work publicly
|
| 407 |
-
- [ ] Final testing in Claude Desktop
|
| 408 |
-
- [ ] Polish documentation
|
| 409 |
-
- [ ] Submit to hackathon
|
| 410 |
-
- [ ] Buffer for last-minute issues
|
| 411 |
-
|
| 412 |
-
---
|
| 413 |
-
|
| 414 |
-
## Technical Stack
|
| 415 |
-
|
| 416 |
-
### Core
|
| 417 |
-
- **Python 3.10+**
|
| 418 |
-
- **Gradio 5.x** (with MCP capabilities)
|
| 419 |
-
- **MCP SDK** (`pip install mcp`)
|
| 420 |
-
- **OpenAI API** (gpt-4o-mini for characters)
|
| 421 |
-
- **Anthropic API** (optional, for variety)
|
| 422 |
-
|
| 423 |
-
### External APIs
|
| 424 |
-
- **Semantic Scholar API** (academic papers) - Free, no key needed
|
| 425 |
-
- **Brave Search API** or **SerpAPI** (web search) - Free tier available
|
| 426 |
-
- **eBird API** (bird sightings) - Free with registration
|
| 427 |
-
- **OpenWeather API** (weather data) - Free tier
|
| 428 |
-
- **News API** (news search) - Free tier
|
| 429 |
-
|
| 430 |
-
### Development Tools
|
| 431 |
-
- **MCP Inspector** (for testing MCP tools)
|
| 432 |
-
- **Claude Desktop** (for testing external tool usage)
|
| 433 |
-
- **Git/GitHub** (version control)
|
| 434 |
-
- **HF Spaces** (deployment)
|
| 435 |
-
|
| 436 |
-
---
|
| 437 |
-
|
| 438 |
-
## File Structure
|
| 439 |
-
|
| 440 |
-
```
|
| 441 |
-
corvid-council/
|
| 442 |
-
├── README.md
|
| 443 |
-
├── requirements.txt
|
| 444 |
-
├── app.py # Main Gradio app
|
| 445 |
-
├── .env.example # API key template
|
| 446 |
-
├── src/
|
| 447 |
-
│ ├── __init__.py
|
| 448 |
-
│ ├── orchestrator.py # CouncilOrchestrator
|
| 449 |
-
│ ├── character.py # Character base class
|
| 450 |
-
│ ├── characters/
|
| 451 |
-
│ │ ├── __init__.py
|
| 452 |
-
│ │ ├── corvus.py # Corvus implementation
|
| 453 |
-
│ │ ├── magpie.py # Magpie implementation
|
| 454 |
-
│ │ ├── raven.py # Raven implementation
|
| 455 |
-
│ │ └── crow.py # Crow implementation
|
| 456 |
-
│ ├── mcp/
|
| 457 |
-
│ │ ├── __init__.py
|
| 458 |
-
│ │ ├── server.py # Internal MCP server
|
| 459 |
-
│ │ ├── tools/
|
| 460 |
-
│ │ │ ├── academic.py # Corvus tools
|
| 461 |
-
│ │ │ ├── social.py # Magpie tools
|
| 462 |
-
│ │ │ ├── realtime.py # Raven tools
|
| 463 |
-
│ │ │ └── observational.py # Crow tools
|
| 464 |
-
│ │ └── external.py # External MCP tools (exposed by app)
|
| 465 |
-
│ ├── ui/
|
| 466 |
-
│ │ ├── __init__.py
|
| 467 |
-
│ │ ├── interface.py # Gradio interface
|
| 468 |
-
│ │ └── components.py # Custom UI components
|
| 469 |
-
│ └── utils/
|
| 470 |
-
│ ├── __init__.py
|
| 471 |
-
│ ├── prompts.py # System prompts for characters
|
| 472 |
-
│ └── helpers.py # Utility functions
|
| 473 |
-
└── tests/
|
| 474 |
-
├── test_orchestrator.py
|
| 475 |
-
├── test_characters.py
|
| 476 |
-
└── test_mcp_tools.py
|
| 477 |
-
```
|
| 478 |
-
|
| 479 |
-
---
|
| 480 |
-
|
| 481 |
-
## Key Implementation Patterns
|
| 482 |
-
|
| 483 |
-
### Pattern 1: Staggered Responses
|
| 484 |
-
```python
|
| 485 |
-
async def generate_responses(question, characters):
|
| 486 |
-
"""Characters respond one at a time with delays"""
|
| 487 |
-
responses = []
|
| 488 |
-
|
| 489 |
-
for i, character in enumerate(characters):
|
| 490 |
-
# Show typing indicator
|
| 491 |
-
show_typing(character.name)
|
| 492 |
-
|
| 493 |
-
# Delay based on message length
|
| 494 |
-
await asyncio.sleep(random.uniform(2, 5))
|
| 495 |
-
|
| 496 |
-
# Generate response (includes tool usage)
|
| 497 |
-
response = await character.research_and_respond(
|
| 498 |
-
question,
|
| 499 |
-
context=responses # See previous responses
|
| 500 |
-
)
|
| 501 |
-
|
| 502 |
-
responses.append(response)
|
| 503 |
-
|
| 504 |
-
return responses
|
| 505 |
-
```
|
| 506 |
-
|
| 507 |
-
### Pattern 2: Tool Usage Display
|
| 508 |
-
```python
|
| 509 |
-
async def use_tools_with_display(character, tools_to_use):
|
| 510 |
-
"""Show tool usage in UI"""
|
| 511 |
-
results = []
|
| 512 |
-
|
| 513 |
-
for tool in tools_to_use:
|
| 514 |
-
# Show in UI: "Corvus is searching papers..."
|
| 515 |
-
update_ui(f"{character.name} is using {tool.name}...")
|
| 516 |
-
|
| 517 |
-
try:
|
| 518 |
-
result = await mcp_client.call_tool(tool.name, tool.params)
|
| 519 |
-
results.append(result)
|
| 520 |
-
except Exception as e:
|
| 521 |
-
# Show error gracefully
|
| 522 |
-
update_ui(f"⚠️ Tool {tool.name} failed, continuing...")
|
| 523 |
-
|
| 524 |
-
return results
|
| 525 |
-
```
|
| 526 |
-
|
| 527 |
-
### Pattern 3: Character Decides Which Tools
|
| 528 |
-
```python
|
| 529 |
-
async def research_and_respond(self, question, context):
|
| 530 |
-
"""Character decides which tools to use"""
|
| 531 |
-
|
| 532 |
-
# Ask LLM what tools to use
|
| 533 |
-
tool_plan = await self.llm.generate(
|
| 534 |
-
system_prompt=self.system_prompt,
|
| 535 |
-
user_prompt=f"""
|
| 536 |
-
Question: {question}
|
| 537 |
-
Available tools: {self.tools}
|
| 538 |
-
|
| 539 |
-
Which tools should you use? Return JSON list.
|
| 540 |
-
"""
|
| 541 |
-
)
|
| 542 |
-
|
| 543 |
-
# Execute chosen tools
|
| 544 |
-
tool_results = await self.execute_tools(tool_plan)
|
| 545 |
-
|
| 546 |
-
# Generate response using results
|
| 547 |
-
message = await self.llm.generate(
|
| 548 |
-
system_prompt=self.system_prompt,
|
| 549 |
-
user_prompt=f"""
|
| 550 |
-
Question: {question}
|
| 551 |
-
Tool results: {tool_results}
|
| 552 |
-
|
| 553 |
-
Write your response in character.
|
| 554 |
-
"""
|
| 555 |
-
)
|
| 556 |
-
|
| 557 |
-
return message
|
| 558 |
-
```
|
| 559 |
-
|
| 560 |
-
### Pattern 4: Consensus Synthesis
|
| 561 |
-
```python
|
| 562 |
-
async def synthesize_consensus(self, responses):
|
| 563 |
-
"""Create unified answer for MCP calls"""
|
| 564 |
-
|
| 565 |
-
# Extract key points from each response
|
| 566 |
-
synthesis_prompt = f"""
|
| 567 |
-
Four experts answered the same question. Synthesize their responses:
|
| 568 |
-
|
| 569 |
-
Corvus (Academic): {responses['corvus']}
|
| 570 |
-
Magpie (Social): {responses['magpie']}
|
| 571 |
-
Raven (Activist): {responses['raven']}
|
| 572 |
-
Crow (Observer): {responses['crow']}
|
| 573 |
-
|
| 574 |
-
Create a consensus answer that:
|
| 575 |
-
- Combines their insights
|
| 576 |
-
- Notes where they agree/disagree
|
| 577 |
-
- Includes all sources
|
| 578 |
-
- Rates overall confidence
|
| 579 |
-
"""
|
| 580 |
-
|
| 581 |
-
return await llm.generate(synthesis_prompt)
|
| 582 |
-
```
|
| 583 |
-
|
| 584 |
-
---
|
| 585 |
-
|
| 586 |
-
## Common Pitfalls & Solutions
|
| 587 |
-
|
| 588 |
-
### Pitfall 1: Rate Limiting
|
| 589 |
-
**Problem**: Hitting API rate limits with multiple characters
|
| 590 |
-
|
| 591 |
-
**Solutions**:
|
| 592 |
-
- Stagger API calls (2-3 seconds apart)
|
| 593 |
-
- Use cheaper models (gpt-4o-mini)
|
| 594 |
-
- Cache tool results
|
| 595 |
-
- Implement exponential backoff
|
| 596 |
-
|
| 597 |
-
### Pitfall 2: Tool Failures
|
| 598 |
-
**Problem**: External API is down or returns error
|
| 599 |
-
|
| 600 |
-
**Solutions**:
|
| 601 |
-
- Always wrap tool calls in try-except
|
| 602 |
-
- Have fallback responses
|
| 603 |
-
- Show errors gracefully to user
|
| 604 |
-
- Continue conversation even if one tool fails
|
| 605 |
-
|
| 606 |
-
### Pitfall 3: Repetitive Conversations
|
| 607 |
-
**Problem**: Characters say similar things
|
| 608 |
-
|
| 609 |
-
**Solutions**:
|
| 610 |
-
- Strong, distinct system prompts
|
| 611 |
-
- Different tool sets force different perspectives
|
| 612 |
-
- Include context of previous responses
|
| 613 |
-
- Add personality quirks (Magpie posts old news, etc.)
|
| 614 |
-
|
| 615 |
-
### Pitfall 4: Slow Responses
|
| 616 |
-
**Problem**: Waiting for multiple LLM + tool calls is slow
|
| 617 |
-
|
| 618 |
-
**Solutions**:
|
| 619 |
-
- Show typing indicators
|
| 620 |
-
- Stream responses where possible
|
| 621 |
-
- Call tools in parallel when they don't depend on each other
|
| 622 |
-
- Pre-generate demo scenarios for judging
|
| 623 |
-
|
| 624 |
-
### Pitfall 5: MCP Exposure Not Working
|
| 625 |
-
**Problem**: External apps can't call your tools
|
| 626 |
-
|
| 627 |
-
**Solutions**:
|
| 628 |
-
- Test with MCP Inspector first
|
| 629 |
-
- Check CORS settings
|
| 630 |
-
- Verify tool schemas are valid
|
| 631 |
-
- Ensure server is publicly accessible
|
| 632 |
-
- Check HF Spaces networking settings
|
| 633 |
-
|
| 634 |
-
---
|
| 635 |
-
|
| 636 |
-
## Testing Strategy
|
| 637 |
-
|
| 638 |
-
### Unit Tests
|
| 639 |
-
- Individual tools return expected format
|
| 640 |
-
- Characters generate appropriate responses
|
| 641 |
-
- Orchestrator handles edge cases
|
| 642 |
-
|
| 643 |
-
### Integration Tests
|
| 644 |
-
- Full conversation flow works
|
| 645 |
-
- Both interfaces (UI and MCP) work
|
| 646 |
-
- Tool failures handled gracefully
|
| 647 |
-
|
| 648 |
-
### Manual Testing Scenarios
|
| 649 |
-
|
| 650 |
-
**Scenario 1: Basic Question**
|
| 651 |
-
- Ask: "Are crows smart?"
|
| 652 |
-
- Expect: All 4 respond, use tools, cite sources
|
| 653 |
-
|
| 654 |
-
**Scenario 2: Fact-Checking**
|
| 655 |
-
- Magpie posts dubious claim
|
| 656 |
-
- Expect: Corvus or Raven fact-checks it
|
| 657 |
-
|
| 658 |
-
**Scenario 3: External MCP Call**
|
| 659 |
-
- From Claude Desktop: call `ask_crow_council("Do crows use tools?")`
|
| 660 |
-
- Expect: Structured response with consensus
|
| 661 |
-
|
| 662 |
-
**Scenario 4: Old News**
|
| 663 |
-
- Magpie shares old content
|
| 664 |
-
- Expect: Others notice and comment (first few times)
|
| 665 |
-
|
| 666 |
-
**Scenario 5: Tool Failure**
|
| 667 |
-
- Simulate API down
|
| 668 |
-
- Expect: Graceful degradation, conversation continues
|
| 669 |
-
|
| 670 |
-
---
|
| 671 |
-
|
| 672 |
-
## Demo Script
|
| 673 |
-
|
| 674 |
-
### Demo 1: Gradio UI (2 minutes)
|
| 675 |
-
1. Open interface, introduce the four experts
|
| 676 |
-
2. Ask: "Can crows recognize individual humans?"
|
| 677 |
-
3. Show:
|
| 678 |
-
- Characters using different tools
|
| 679 |
-
- Tool usage indicators
|
| 680 |
-
- Different personality styles
|
| 681 |
-
- Sources and citations
|
| 682 |
-
4. Highlight: Real-time research, transparent process
|
| 683 |
-
|
| 684 |
-
### Demo 2: MCP Tool Usage (2 minutes)
|
| 685 |
-
1. Switch to Claude Desktop
|
| 686 |
-
2. Show available tools: `ask_crow_council`, etc.
|
| 687 |
-
3. Ask same question through MCP tool
|
| 688 |
-
4. Show:
|
| 689 |
-
- Same backend process (quick view of Gradio)
|
| 690 |
-
- Structured response returned
|
| 691 |
-
- Synthesized consensus with sources
|
| 692 |
-
5. Highlight: Same intelligence, two interfaces
|
| 693 |
-
|
| 694 |
-
### Demo 3: Architecture Explanation (1 minute)
|
| 695 |
-
1. Show diagram
|
| 696 |
-
2. Explain: MCP tools consuming MCP tools
|
| 697 |
-
3. Point out: Composability, extensibility
|
| 698 |
-
4. Mention: Could add more experts, more tools
|
| 699 |
-
|
| 700 |
-
---
|
| 701 |
-
|
| 702 |
-
## Success Criteria
|
| 703 |
-
|
| 704 |
-
### Minimum Viable Product (Must Have)
|
| 705 |
-
- ✅ 4 characters with distinct personalities
|
| 706 |
-
- ✅ 8-10 working MCP tools (2-3 per character)
|
| 707 |
-
- ✅ Gradio chat interface
|
| 708 |
-
- ✅ External MCP tool exposure (ask_crow_council)
|
| 709 |
-
- ✅ Both interfaces work reliably
|
| 710 |
-
- ✅ Deployed to HF Spaces
|
| 711 |
-
- ✅ Good README and demo
|
| 712 |
-
|
| 713 |
-
### Stretch Goals (Nice to Have)
|
| 714 |
-
- ✅ 12-15 tools (full tool sets)
|
| 715 |
-
- ✅ Tool chaining (one tool's output → another)
|
| 716 |
-
- ✅ Advanced interaction patterns (quirk decay)
|
| 717 |
-
- ✅ Memory across sessions
|
| 718 |
-
- ✅ Beautiful UI with animations
|
| 719 |
-
- ✅ Comprehensive error handling
|
| 720 |
-
|
| 721 |
-
### Judging Criteria (What Matters)
|
| 722 |
-
1. **Technical sophistication**: Multi-tool MCP system
|
| 723 |
-
2. **Creativity**: Novel use of MCP (agents-as-tools)
|
| 724 |
-
3. **Completeness**: Both interfaces work well
|
| 725 |
-
4. **Demo quality**: Clear, impressive, functional
|
| 726 |
-
5. **Documentation**: Easy to understand and extend
|
| 727 |
-
|
| 728 |
-
---
|
| 729 |
-
|
| 730 |
-
## Resources
|
| 731 |
-
|
| 732 |
-
### APIs
|
| 733 |
-
- Semantic Scholar: https://api.semanticscholar.org/
|
| 734 |
-
- eBird: https://documenter.getpostman.com/view/664302/S1ENwy59
|
| 735 |
-
- OpenWeather: https://openweathermap.org/api
|
| 736 |
-
- News API: https://newsapi.org/
|
| 737 |
-
|
| 738 |
-
### Documentation
|
| 739 |
-
- MCP Spec: https://spec.modelcontextprotocol.io/
|
| 740 |
-
- Gradio Docs: https://www.gradio.app/docs
|
| 741 |
-
- HF Course: https://huggingface.co/learn/mcp-course/
|
| 742 |
-
|
| 743 |
-
### Tools
|
| 744 |
-
- MCP Inspector: (check course for link)
|
| 745 |
-
- Claude Desktop: https://claude.ai/download
|
| 746 |
-
|
| 747 |
-
---
|
| 748 |
-
|
| 749 |
-
## Quick Start Commands
|
| 750 |
-
|
| 751 |
-
```bash
|
| 752 |
-
# Clone and setup
|
| 753 |
-
git clone <your-repo>
|
| 754 |
-
cd corvid-council
|
| 755 |
-
pip install -r requirements.txt
|
| 756 |
-
|
| 757 |
-
# Set up environment
|
| 758 |
-
cp .env.example .env
|
| 759 |
-
# Edit .env with your API keys
|
| 760 |
-
|
| 761 |
-
# Run locally
|
| 762 |
-
python app.py
|
| 763 |
-
|
| 764 |
-
# Deploy to HF Spaces
|
| 765 |
-
git push hf main
|
| 766 |
-
```
|
| 767 |
-
|
| 768 |
-
---
|
| 769 |
-
|
| 770 |
-
## Support Checklist for LLMs
|
| 771 |
-
|
| 772 |
-
When asking an LLM for help, provide:
|
| 773 |
-
- [ ] This development guide
|
| 774 |
-
- [ ] Specific file you're working on
|
| 775 |
-
- [ ] Error message if debugging
|
| 776 |
-
- [ ] What you've tried already
|
| 777 |
-
- [ ] Specific question or task
|
| 778 |
-
|
| 779 |
-
**Example prompt**:
|
| 780 |
-
```
|
| 781 |
-
I'm building the Corvid Council project (see attached dev guide).
|
| 782 |
-
I'm working on [specific component].
|
| 783 |
-
I'm trying to [specific task].
|
| 784 |
-
I'm getting [error/issue].
|
| 785 |
-
I've tried [what you tried].
|
| 786 |
-
Can you help me [specific ask]?
|
| 787 |
-
```
|
| 788 |
-
|
| 789 |
-
---
|
| 790 |
-
|
| 791 |
-
## Contact & Resources
|
| 792 |
-
|
| 793 |
-
**Hackathon**: Gradio Agents & MCP Hackathon - Winter 25
|
| 794 |
-
**Track**: Building MCP (Creative)
|
| 795 |
-
**Tag**: `building-mcp-track-creative`
|
| 796 |
-
|
| 797 |
-
Good luck! Build something amazing. 🎯
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
notes_etc/development_guide_02.txt
DELETED
|
@@ -1,181 +0,0 @@
|
|
| 1 |
-
Project Overview
|
| 2 |
-
|
| 3 |
-
Name: Cluas
|
| 4 |
-
Hackathon / Track: Gradio Agents & MCP Hackathon – Winter 25, Creative Track
|
| 5 |
-
Concept: A multi-agent MCP system where four AI “crow experts” discuss topics, each using specialized tools. Users can either observe the panel in a Gradio chat interface or query it programmatically via MCP.
|
| 6 |
-
|
| 7 |
-
Hook:
|
| 8 |
-
“What if you could consult a panel of AI experts that not only debates, researches, and cross-verifies claims but also maintains a shared memory across sessions?”
|
| 9 |
-
|
| 10 |
-
Architecture Overview
|
| 11 |
-
External User/App (Claude Desktop, etc.)
|
| 12 |
-
↓ (calls MCP tool)
|
| 13 |
-
ask_crow_council(question)
|
| 14 |
-
↓
|
| 15 |
-
Gradio App (MCP server)
|
| 16 |
-
↓
|
| 17 |
-
CouncilOrchestrator
|
| 18 |
-
↓
|
| 19 |
-
4 Character Agents (Corvus, Magpie, Raven, Crow)
|
| 20 |
-
↓
|
| 21 |
-
Character-Specific MCP Tools (~12–15 total)
|
| 22 |
-
↓
|
| 23 |
-
External APIs (Semantic Scholar, eBird, Weather, News)
|
| 24 |
-
↓
|
| 25 |
-
Shared AgentMemory (JSON / DB)
|
| 26 |
-
↓
|
| 27 |
-
Synthesized Response → User
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
Key Differences vs. earlier plan:
|
| 31 |
-
|
| 32 |
-
AgentMemory is first-class: acts as shared context, not just caching.
|
| 33 |
-
|
| 34 |
-
Cache is memory: supports cross-agent recall, deduplication, “didn’t we discuss this?”
|
| 35 |
-
|
| 36 |
-
Tool orchestration is separate from UI: backend drives both Gradio interface and MCP endpoint.
|
| 37 |
-
|
| 38 |
-
Characters
|
| 39 |
-
Character Role Personality Core Tools Behavior
|
| 40 |
-
Corvus Scholar Analytical, cautious, thorough search_academic, get_paper_details, verify_claim, citation_network Reads literature, fact-checks, posts rarely but substantively
|
| 41 |
-
Magpie Enthusiast Social, rapid-fire, excited search_social, search_web, find_trending Posts frequently, may repeat info, creates conversational energy
|
| 42 |
-
Raven Activist Urgent, confrontational, data-driven get_environmental_data, search_news, fact_check_claim, analyze_sentiment Searches real-time threats, challenges others’ claims
|
| 43 |
-
Crow Observer Calm, patient, contemplative get_sightings, get_weather_patterns, analyze_temporal_patterns Rarely posts, synthesizes patterns, provides perspective
|
| 44 |
-
|
| 45 |
-
Notes:
|
| 46 |
-
|
| 47 |
-
Each character writes in a distinct voice.
|
| 48 |
-
|
| 49 |
-
AgentMemory is referenced when appropriate to recall past papers, claims, or events.
|
| 50 |
-
|
| 51 |
-
Tools are abstracted behind MCP methods for modularity.
|
| 52 |
-
|
| 53 |
-
MCP Tool Architecture
|
| 54 |
-
|
| 55 |
-
Internal MCP Tools (Character Tools):
|
| 56 |
-
|
| 57 |
-
Academic (Corvus): 4 tools
|
| 58 |
-
|
| 59 |
-
Social/Web (Magpie): 3 tools
|
| 60 |
-
|
| 61 |
-
Real-time Data (Raven): 4 tools
|
| 62 |
-
|
| 63 |
-
Observational (Crow): 3 tools
|
| 64 |
-
|
| 65 |
-
External MCP Tools (Exposed via Gradio App):
|
| 66 |
-
|
| 67 |
-
@mcp.tool()
|
| 68 |
-
async def ask_crow_council(question: str) -> dict:
|
| 69 |
-
"""Consult all 4 characters; return synthesized response with sources."""
|
| 70 |
-
|
| 71 |
-
@mcp.tool()
|
| 72 |
-
async def ask_specific_expert(question: str, expert: Literal["corvus", "magpie", "raven", "crow"]) -> dict:
|
| 73 |
-
"""Query a single character."""
|
| 74 |
-
|
| 75 |
-
@mcp.tool()
|
| 76 |
-
async def fact_check_claim(claim: str) -> dict:
|
| 77 |
-
"""Have the council verify a claim using AgentMemory and tools."""
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
AgentMemory Integration:
|
| 81 |
-
|
| 82 |
-
Logs items with metadata: title, DOI/arXiv link, snippet, timestamp, tags.
|
| 83 |
-
|
| 84 |
-
Retrieval methods: get_recent(days), get_by_tag(tag), search_title(query).
|
| 85 |
-
|
| 86 |
-
Can prune old memories; supports both short-term and long-term context.
|
| 87 |
-
|
| 88 |
-
Project Structure (Updated for Modularity)
|
| 89 |
-
cluas/
|
| 90 |
-
├── README.md
|
| 91 |
-
├── .env.example
|
| 92 |
-
├── src/
|
| 93 |
-
│ ├── __init__.py
|
| 94 |
-
│ ├── orchestrator.py # CouncilOrchestrator
|
| 95 |
-
│ ├── character.py # Character base class
|
| 96 |
-
│ ├── characters/
|
| 97 |
-
│ │ ├── corvus.py
|
| 98 |
-
│ │ ├── magpie.py
|
| 99 |
-
│ │ ├── raven.py
|
| 100 |
-
│ │ └── crow.py
|
| 101 |
-
│ ├── mcp/
|
| 102 |
-
│ │ ├── server.py # Internal MCP server
|
| 103 |
-
│ │ ├── tools/
|
| 104 |
-
│ │ │ ├── academic.py
|
| 105 |
-
│ │ │ ├── social.py
|
| 106 |
-
│ │ │ ├── realtime.py
|
| 107 |
-
│ │ │ └── observational.py
|
| 108 |
-
│ │ └── external.py # Exposed MCP tools
|
| 109 |
-
│ ├── memory/
|
| 110 |
-
│ │ └── agent_memory.py # Shared memory / cache
|
| 111 |
-
│ ├── ui/
|
| 112 |
-
│ │ ├── interface.py
|
| 113 |
-
│ │ └── components.py
|
| 114 |
-
│ └── utils/
|
| 115 |
-
│ ├── prompts.py
|
| 116 |
-
│ └── helpers.py
|
| 117 |
-
└── tests/
|
| 118 |
-
├── test_orchestrator.py
|
| 119 |
-
├── test_characters.py
|
| 120 |
-
└── test_agent_memory.py
|
| 121 |
-
|
| 122 |
-
Development Phases (Current Scope)
|
| 123 |
-
Phase 1 – Core MVP
|
| 124 |
-
|
| 125 |
-
Corvus implemented with 2 academic tools.
|
| 126 |
-
|
| 127 |
-
Basic AgentMemory operational (short-term storage).
|
| 128 |
-
|
| 129 |
-
Basic Gradio chat interface.
|
| 130 |
-
|
| 131 |
-
Tool orchestration scaffolding in place.
|
| 132 |
-
|
| 133 |
-
Phase 2 – Additional Characters & Tools
|
| 134 |
-
|
| 135 |
-
Add Magpie and Raven with partial tools.
|
| 136 |
-
|
| 137 |
-
Implement staggered responses, typing indicators.
|
| 138 |
-
|
| 139 |
-
Ensure memory integration across agents.
|
| 140 |
-
|
| 141 |
-
Phase 3 – Full Council & MCP Exposure
|
| 142 |
-
|
| 143 |
-
Crow added.
|
| 144 |
-
|
| 145 |
-
Expose ask_crow_council() and ask_specific_expert().
|
| 146 |
-
|
| 147 |
-
Test multi-agent synthesis and external calls.
|
| 148 |
-
|
| 149 |
-
Phase 4 – Polish & Deploy
|
| 150 |
-
|
| 151 |
-
Error handling, retries, and rate limiting.
|
| 152 |
-
|
| 153 |
-
Memory pruning, long-term storage optional (Supabase / MongoDB).
|
| 154 |
-
|
| 155 |
-
UI/UX polish for Gradio.
|
| 156 |
-
|
| 157 |
-
Demo-ready, hackathon-ready deployment.
|
| 158 |
-
|
| 159 |
-
Key Implementation Patterns
|
| 160 |
-
|
| 161 |
-
Tool orchestration per character – each agent decides which tools to use, executes asynchronously.
|
| 162 |
-
|
| 163 |
-
Staggered responses – enhances human-like timing.
|
| 164 |
-
|
| 165 |
-
Memory-driven context – prior discussions inform current responses.
|
| 166 |
-
|
| 167 |
-
Consensus synthesis – LLM generates unified response for MCP output.
|
| 168 |
-
|
| 169 |
-
Technical Stack
|
| 170 |
-
|
| 171 |
-
Python 3.13 (uv-managed)
|
| 172 |
-
|
| 173 |
-
Gradio 5.x with MCP
|
| 174 |
-
|
| 175 |
-
MCP SDK for server and tools
|
| 176 |
-
|
| 177 |
-
LLM: gpt-4o-mini (Anthropic optional)
|
| 178 |
-
|
| 179 |
-
APIs: Semantic Scholar, eBird, News API, OpenWeather
|
| 180 |
-
|
| 181 |
-
Data/Memory: JSON for now, possible future DB (Supabase or MongoDB)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
notes_etc/exposing_cluas_as_an_MCP.py
DELETED
|
@@ -1,14 +0,0 @@
|
|
| 1 |
-
# figure something a bit like this
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
@mcp.tool()
|
| 5 |
-
async def ask_crow_council(question: str) -> dict:
|
| 6 |
-
"""Consult all 4 characters; return synthesized response with sources."""
|
| 7 |
-
|
| 8 |
-
@mcp.tool()
|
| 9 |
-
async def ask_specific_expert(question: str, expert: Literal["corvus", "magpie", "raven", "crow"]) -> dict:
|
| 10 |
-
"""Query a single character."""
|
| 11 |
-
|
| 12 |
-
@mcp.tool()
|
| 13 |
-
async def fact_check_claim(claim: str) -> dict:
|
| 14 |
-
"""Have the council verify a claim using AgentMemory and tools."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
notes_etc/possible_architecture_diagram.txt
DELETED
|
@@ -1,48 +0,0 @@
|
|
| 1 |
-
┌─────────────────────────────────────┐
|
| 2 |
-
│ User / Client │
|
| 3 |
-
│ (Claude Desktop, App, API caller) │
|
| 4 |
-
└────────────────────┬────────────────┘
|
| 5 |
-
│ ask_council()
|
| 6 |
-
▼
|
| 7 |
-
┌─────────────────────────────────────┐
|
| 8 |
-
│ Corvid Council MCP Server │
|
| 9 |
-
│ (Gradio chat + MCP tool handler) │
|
| 10 |
-
└────────────────────┬────────────────┘
|
| 11 |
-
│ orchestrates
|
| 12 |
-
▼
|
| 13 |
-
┌─────────────────────────────────────┐
|
| 14 |
-
│ Council Orchestrator │
|
| 15 |
-
│ - Calls individual agents │
|
| 16 |
-
│ - Coordinates group chat flow │
|
| 17 |
-
└────────────────────┬────────────────┘
|
| 18 |
-
│
|
| 19 |
-
┌───────────────────────────┼─────────────────────────────┐
|
| 20 |
-
▼ ▼ ▼
|
| 21 |
-
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
| 22 |
-
│ Corvus │ │ Magpie │ │ Raven │
|
| 23 |
-
│ (Academic AI) │ │ (Trends AI) │ │ (Deep-Focus AI)│
|
| 24 |
-
│ PubMed/S2 API │ │ Web/Social API │ │ Feeds/Alerts │
|
| 25 |
-
└───────┬─────────┘ └───────┬─────────┘ └───────┬─────────┘
|
| 26 |
-
│ │ │
|
| 27 |
-
└──────────────┬────────────┴────────────┬───────────────┘
|
| 28 |
-
▼ ▼
|
| 29 |
-
┌─────────────────────────────────────┐
|
| 30 |
-
│ Agent Memory │
|
| 31 |
-
│ (shared JSON/DB knowledge log) │
|
| 32 |
-
│ - recent papers, trends, facts │
|
| 33 |
-
│ - tags, timestamps, DOIs │
|
| 34 |
-
│ - enables recall & “inside jokes” │
|
| 35 |
-
└─────────────────────────────────────┘
|
| 36 |
-
│
|
| 37 |
-
▼
|
| 38 |
-
┌─────────────────────────────────────┐
|
| 39 |
-
│ LLM Consensus Layer │
|
| 40 |
-
│ - builds final group answer │
|
| 41 |
-
│ - personality + expertise mixing │
|
| 42 |
-
└─────────────────────────────────────┘
|
| 43 |
-
│
|
| 44 |
-
▼
|
| 45 |
-
┌─────────────────────────────────────┐
|
| 46 |
-
│ Final Output │
|
| 47 |
-
│ (chat replay + structured answer) │
|
| 48 |
-
└─────────────────────────────────────┘
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
notes_etc/possible_project_structure.txt
DELETED
|
@@ -1,32 +0,0 @@
|
|
| 1 |
-
corvid-council/
|
| 2 |
-
├── README.md
|
| 3 |
-
├── .env.example
|
| 4 |
-
├── src/
|
| 5 |
-
│ ├── __init__.py
|
| 6 |
-
│ ├── orchestrator.py # CouncilOrchestrator
|
| 7 |
-
│ ├── character.py # Character base class
|
| 8 |
-
│ ├── characters/
|
| 9 |
-
│ │ ├── corvus.py
|
| 10 |
-
│ │ ├── magpie.py
|
| 11 |
-
│ │ ├── raven.py
|
| 12 |
-
│ │ └── crow.py
|
| 13 |
-
│ ├── mcp/
|
| 14 |
-
│ │ ├── server.py # Internal MCP server
|
| 15 |
-
│ │ ├── tools/
|
| 16 |
-
│ │ │ ├── academic.py
|
| 17 |
-
│ │ │ ├── social.py
|
| 18 |
-
│ │ │ ├── realtime.py
|
| 19 |
-
│ │ │ └── observational.py
|
| 20 |
-
│ │ └── external.py # Exposed MCP tools
|
| 21 |
-
│ ├── memory/
|
| 22 |
-
│ │ └── agent_memory.py # Shared memory / cache
|
| 23 |
-
│ ├── ui/
|
| 24 |
-
│ │ ├── interface.py
|
| 25 |
-
│ │ └── components.py
|
| 26 |
-
│ └── utils/
|
| 27 |
-
│ ├── prompts.py
|
| 28 |
-
│ └── helpers.py
|
| 29 |
-
└── tests/
|
| 30 |
-
├── test_orchestrator.py
|
| 31 |
-
├── test_characters.py
|
| 32 |
-
└── test_agent_memory.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pyproject.toml
CHANGED
|
@@ -5,6 +5,7 @@ description = "Add your description here"
|
|
| 5 |
readme = "README.md"
|
| 6 |
requires-python = ">=3.13"
|
| 7 |
dependencies = [
|
|
|
|
| 8 |
"feedparser>=6.0.12",
|
| 9 |
"gradio[mcp,oauth]==6.0.0.dev4",
|
| 10 |
"mcp>=1.20.0",
|
|
|
|
| 5 |
readme = "README.md"
|
| 6 |
requires-python = ">=3.13"
|
| 7 |
dependencies = [
|
| 8 |
+
"fastmcp>=2.13.1",
|
| 9 |
"feedparser>=6.0.12",
|
| 10 |
"gradio[mcp,oauth]==6.0.0.dev4",
|
| 11 |
"mcp>=1.20.0",
|
reviews/changes.md
DELETED
|
@@ -1,220 +0,0 @@
|
|
| 1 |
-
# Change Log
|
| 2 |
-
|
| 3 |
-
**Date:** 2025-11-15
|
| 4 |
-
|
| 5 |
-
This document tracks notable changes in the "Corvid Council" repository.
|
| 6 |
-
|
| 7 |
-
---
|
| 8 |
-
|
| 9 |
-
### November 15, 2025
|
| 10 |
-
|
| 11 |
-
#### Summary of Changes
|
| 12 |
-
|
| 13 |
-
A code snippet related to a potential PubMed API implementation was added as comments to `src/cluas_mcp/common/api_clients.py`. No other functional or structural changes were observed in the repository. The core logic, file structure, and administrative files (`README.md`, `.gitignore`, `requirements.txt`) remain the same as the last review.
|
| 14 |
-
|
| 15 |
-
#### Detailed Changes
|
| 16 |
-
|
| 17 |
-
- **Modified `src/cluas_mcp/common/api_clients.py`**:
|
| 18 |
-
- A block of commented-out Python code was added. This code demonstrates how to use the `Bio.Entrez` library to search PubMed for articles related to corvids, parse the results, and extract details like title, authors, abstract, and DOI.
|
| 19 |
-
|
| 20 |
-
#### Analysis
|
| 21 |
-
|
| 22 |
-
- **Significant:**
|
| 23 |
-
- The change itself is minor (it's only comments), but it's significant in what it signals: active exploration of how to implement the `PubMedClient`. This is a direct move towards fulfilling one of the key requirements for making the `Corvus` character fully functional.
|
| 24 |
-
|
| 25 |
-
- **Good:**
|
| 26 |
-
- This is a positive step. It shows that the next phase of development is being actively researched. The example code is relevant and provides a clear path for the real implementation.
|
| 27 |
-
- Using a well-known library like `BioPython` is a good choice for interacting with NCBI services.
|
| 28 |
-
|
| 29 |
-
- **Concerning:**
|
| 30 |
-
- There are no concerns with this change. It's a healthy sign of a project in the early stages of development. The only minor point is that the code is commented out in the main source file rather than being in a separate experimental script, but this is a trivial issue at this stage.
|
| 31 |
-
|
| 32 |
-
---
|
| 33 |
-
|
| 34 |
-
### November 18, 2025
|
| 35 |
-
|
| 36 |
-
#### Summary of Changes
|
| 37 |
-
|
| 38 |
-
A new `notes_etc/` directory was added, containing detailed development guides and an architecture diagram. Crucially, the previously empty `src/cluas_mcp/common/formatting.py` file was implemented, fixing a critical import error.
|
| 39 |
-
|
| 40 |
-
#### Detailed Changes
|
| 41 |
-
|
| 42 |
-
- **New Directory `notes_etc/`**:
|
| 43 |
-
- `development_guide_01.md`: A comprehensive guide detailing the project's concept, architecture, characters, MCP tools, development phases, and technical stack.
|
| 44 |
-
- `development_guide_02.txt`: A more concise version of the guide.
|
| 45 |
-
- `possible_lightweight_architecture_diagram.txt`: A text-based visualization of the system architecture.
|
| 46 |
-
- **Modified `src/cluas_mcp/common/formatting.py`**:
|
| 47 |
-
- Implemented the `snippet_abstract` function to truncate text intelligently.
|
| 48 |
-
- Implemented the `format_authors` function to format author lists.
|
| 49 |
-
|
| 50 |
-
#### Analysis
|
| 51 |
-
|
| 52 |
-
- **Significant:**
|
| 53 |
-
- The implementation of the functions in `formatting.py` is the most significant change, as it directly unblocks the `Corvus` agent and makes a core piece of the application runnable for the first time.
|
| 54 |
-
- The addition of the development guides provides invaluable context and a clear roadmap for the project's future.
|
| 55 |
-
|
| 56 |
-
- **Good:**
|
| 57 |
-
- These changes are overwhelmingly positive. The bug fix is a major step forward, and the planning documents demonstrate a clear and well-thought-out vision for the project. The architecture is sound, and the character-based agent design is creative and well-defined.
|
| 58 |
-
|
| 59 |
-
- **Concerning:**
|
| 60 |
-
- There are no concerning changes. The project is progressing logically and is now in a much better state than before. The next logical step is to implement the placeholder API clients.
|
| 61 |
-
|
| 62 |
-
---
|
| 63 |
-
|
| 64 |
-
### November 18, 2025 (Afternoon)
|
| 65 |
-
|
| 66 |
-
#### Summary of Changes
|
| 67 |
-
|
| 68 |
-
Significant progress has been made on the API clients. The `ArxivClient` has been fully implemented, and the `PubMedClient` now has a functional search method that retrieves article IDs. More planning documents were also added.
|
| 69 |
-
|
| 70 |
-
#### Detailed Changes
|
| 71 |
-
|
| 72 |
-
- **Modified `src/cluas_mcp/common/api_clients.py`**:
|
| 73 |
-
- **`ArxivClient`**: Now contains a full implementation. It builds a query, fetches data from the arXiv API, parses the Atom feed, and returns a list of structured dictionaries containing paper details.
|
| 74 |
-
- **`PubMedClient`**: A `pubmed_search` method has been implemented to perform the `esearch` step of the API interaction. It correctly builds a complex query and uses a helper method `parse_id_list` to extract PubMed IDs from the XML response. The `efetch` step is not yet implemented.
|
| 75 |
-
- **`SemanticScholarClient`**: Remains a placeholder.
|
| 76 |
-
- **New Files in `notes_etc/`**:
|
| 77 |
-
- `possible_architecture_diagram.txt`: A more detailed architecture diagram.
|
| 78 |
-
- `possible_project_structure.txt`: A proposed target file structure.
|
| 79 |
-
- `exposing_cluas_as_an_MCP.py`: A code snippet showing how the app might expose MCP tools.
|
| 80 |
-
|
| 81 |
-
#### Analysis
|
| 82 |
-
|
| 83 |
-
- **Significant:**
|
| 84 |
-
- The implementation of the `ArxivClient` and the first half of the `PubMedClient` is the most significant change. This represents the first major piece of core feature development, moving the project from planning and bug-fixing into active implementation.
|
| 85 |
-
|
| 86 |
-
- **Good:**
|
| 87 |
-
- This is a huge step in the right direction. The code is functional and well-structured. The `Corvus` agent now has a working data source (arXiv) and a partially working one (PubMed). This directly addresses the main blocker and builds momentum.
|
| 88 |
-
|
| 89 |
-
- **Concerning:**
|
| 90 |
-
- There are no concerning changes. The progress is excellent. The clear next step is to complete the `PubMedClient` by adding the `efetch` logic to retrieve full article data using the IDs from `pubmed_search`.
|
| 91 |
-
|
| 92 |
-
---
|
| 93 |
-
|
| 94 |
-
### November 18, 2025 (Late Afternoon)
|
| 95 |
-
|
| 96 |
-
#### Summary of Changes
|
| 97 |
-
|
| 98 |
-
A significant refactoring has occurred. The `PubMedClient` has been moved to a new `academic` submodule, and a robust, retry-enabled HTTP fetching utility has been created in `src/cluas_mcp/common/http.py`.
|
| 99 |
-
|
| 100 |
-
#### Detailed Changes
|
| 101 |
-
|
| 102 |
-
- **New Directory `src/cluas_mcp/academic/`**:
|
| 103 |
-
- The `PubMedClient` has been moved to `src/cluas_mcp/academic/pubmed_client.py`.
|
| 104 |
-
- **New File `src/cluas_mcp/common/http.py`**:
|
| 105 |
-
- This file introduces a `fetch_with_retry` function that uses the `tenacity` library to provide exponential backoff for HTTP requests. This makes API calls more resilient.
|
| 106 |
-
- **Modified `src/cluas_mcp/academic/pubmed_client.py`**:
|
| 107 |
-
- The refactored `PubMedClient` now uses the new `fetch_with_retry` utility for its API calls.
|
| 108 |
-
- **Modified `pyproject.toml`**:
|
| 109 |
-
- The `tenacity` library has been added as a project dependency.
|
| 110 |
-
- **Modified `src/cluas_mcp/common/api_clients.py`**:
|
| 111 |
-
- This file still contains the old `PubMedClient` code, creating duplication.
|
| 112 |
-
|
| 113 |
-
#### Analysis
|
| 114 |
-
|
| 115 |
-
- **Significant:**
|
| 116 |
-
- The architectural refactoring is highly significant. It shows a move towards a more organized, maintainable, and robust codebase, aligning with the project's planning documents. The creation of a shared, resilient HTTP utility is a major improvement.
|
| 117 |
-
|
| 118 |
-
- **Good:**
|
| 119 |
-
- The new `http.py` module is excellent and demonstrates best practices for consuming external APIs.
|
| 120 |
-
- The file structure is becoming cleaner and more logical.
|
| 121 |
-
|
| 122 |
-
- **Concerning:**
|
| 123 |
-
- **Code Duplication:** The most pressing issue is the duplicated `PubMedClient` code. The old implementation in `src/cluas_mcp/common/api_clients.py` is now obsolete and should be removed to prevent confusion and future bugs. The other clients in that file should also be refactored into their own modules.
|
| 124 |
-
|
| 125 |
-
---
|
| 126 |
-
|
| 127 |
-
### November 18, 2025 (Evening)
|
| 128 |
-
|
| 129 |
-
#### Summary of Changes
|
| 130 |
-
|
| 131 |
-
A massive and highly positive refactoring has been completed. The API clients have been fully separated into their own modules, the `PubMedClient` is now feature-complete, a new `AcademicSearch` facade provides a single point of entry, domain keywords have been separated, and—most importantly—tests have been added for the API clients.
|
| 132 |
-
|
| 133 |
-
#### Detailed Changes
|
| 134 |
-
|
| 135 |
-
- **Completed Refactoring**:
|
| 136 |
-
- The API clients now live in `src/cluas_mcp/academic/` as `pubmed.py`, `arxiv.py`, and `semantic_scholar.py`.
|
| 137 |
-
- The old `src/cluas_mcp/common/api_clients.py` file still exists but is now entirely obsolete.
|
| 138 |
-
- **Completed `PubMedClient`**:
|
| 139 |
-
- The client in `academic/pubmed.py` now includes a `fetch_articles` method, completing the `esearch`/`efetch` workflow.
|
| 140 |
-
- **New `AcademicSearch` Facade**:
|
| 141 |
-
- `academic/academic_search.py` provides a single `academic_search` function that calls all underlying clients, simplifying future use.
|
| 142 |
-
- **Domain Knowledge Separation**:
|
| 143 |
-
- `src/cluas_mcp/domain/keywords.py` now stores keyword lists, separating this data from the client logic.
|
| 144 |
-
- **New Tests**:
|
| 145 |
-
- `tests/test_arxiv.py` and `tests/test_pubmed.py` have been added, providing actual tests for the API clients.
|
| 146 |
-
|
| 147 |
-
#### Analysis
|
| 148 |
-
|
| 149 |
-
- **Significant:**
|
| 150 |
-
- This is a pivotal update. The project has rapidly matured from a proof-of-concept to a well-structured and tested data access layer. The addition of tests is the most significant and important change, as it provides a foundation for reliable future development.
|
| 151 |
-
|
| 152 |
-
- **Good:**
|
| 153 |
-
- The architecture is now clean, modular, and extensible.
|
| 154 |
-
- The separation of concerns (clients, domain data, facades) is excellent.
|
| 155 |
-
- The data layer for the `Corvus` agent is now functionally complete and robust.
|
| 156 |
-
|
| 157 |
-
- **Concerning:**
|
| 158 |
-
- The only remaining issue is the obsolete `src/cluas_mcp/common/api_clients.py` file. It should be deleted to finalize the cleanup.
|
| 159 |
-
|
| 160 |
-
---
|
| 161 |
-
|
| 162 |
-
### November 18, 2025 (Night)
|
| 163 |
-
|
| 164 |
-
#### Summary of Changes
|
| 165 |
-
|
| 166 |
-
The final placeholder API client, `SemanticScholarClient`, has been implemented and tested. The data access layer for the `Corvus` agent is now 100% complete.
|
| 167 |
-
|
| 168 |
-
#### Detailed Changes
|
| 169 |
-
|
| 170 |
-
- **`SemanticScholarClient` Implemented**:
|
| 171 |
-
- The client in `src/cluas_mcp/academic/semantic_scholar.py` has been fully implemented. It queries the Semantic Scholar API, requests specific fields, and normalizes the response into the project's standard format.
|
| 172 |
-
- **New Test for `SemanticScholarClient`**:
|
| 173 |
-
- A new test file, `tests/test_semantic_scholar.py`, was added to validate the new client.
|
| 174 |
-
- **`PubMedClient` Improved**:
|
| 175 |
-
- The `pubmed.py` client was improved to extract more data (DOI, PubMed link) and includes better error handling for parsing individual articles.
|
| 176 |
-
- **Facade Renamed**:
|
| 177 |
-
- The `academic_search.py` facade was renamed to `academic_search_entry.py`.
|
| 178 |
-
|
| 179 |
-
#### Analysis
|
| 180 |
-
|
| 181 |
-
- **Significant:**
|
| 182 |
-
- The completion of the final API client is a major milestone. The `academic_search` facade is now fully operational, capable of querying and aggregating results from all three target data sources.
|
| 183 |
-
|
| 184 |
-
- **Good:**
|
| 185 |
-
- The project continues its excellent momentum. The practice of adding tests for all new code is being maintained, which is crucial for long-term stability. The data access layer is now a polished, production-ready component.
|
| 186 |
-
|
| 187 |
-
- **Concerning:**
|
| 188 |
-
- There are no new concerns. The only outstanding task from the refactoring is to delete the obsolete `src/cluas_mcp/common/api_clients.py` file.
|
| 189 |
-
|
| 190 |
-
---
|
| 191 |
-
|
| 192 |
-
### November 18, 2025 (Final)
|
| 193 |
-
|
| 194 |
-
#### Summary of Changes
|
| 195 |
-
|
| 196 |
-
This update finalizes the data access layer by improving the test infrastructure and cleaning up the last piece of technical debt.
|
| 197 |
-
|
| 198 |
-
#### Detailed Changes
|
| 199 |
-
|
| 200 |
-
- **Test Suite Refactoring**:
|
| 201 |
-
* Tests for individual API clients have been moved to a dedicated `tests/clients/` directory.
|
| 202 |
-
* A new `tests/integration/` directory was created for higher-level tests, starting with a test for the `academic_search_entrypoint`.
|
| 203 |
-
* A `tests/conftest.py` file was added to manage the system path for the test suite, a standard best practice.
|
| 204 |
-
- **Facade Hardening**:
|
| 205 |
-
* The `academic_search_entrypoint` was improved with `try...except` blocks to ensure that a failure in one API client does not prevent the others from returning results.
|
| 206 |
-
- **Technical Debt Removed**:
|
| 207 |
-
* The obsolete `src/cluas_mcp/common/api_clients.py` file has been deleted.
|
| 208 |
-
- **Dependencies Formalized**:
|
| 209 |
-
* `pytest` was officially added to the `pyproject.toml` dependencies.
|
| 210 |
-
|
| 211 |
-
#### Analysis
|
| 212 |
-
|
| 213 |
-
- **Significant:**
|
| 214 |
-
- The cleanup of the final piece of technical debt and the formalization of a layered testing strategy mark the official completion of the data access layer. This component is now stable, robust, and maintainable.
|
| 215 |
-
|
| 216 |
-
- **Good:**
|
| 217 |
-
- All changes are positive and demonstrate a commitment to high-quality, professional software development practices. The separation of client-level tests from integration tests is particularly noteworthy.
|
| 218 |
-
|
| 219 |
-
- **Concerning:**
|
| 220 |
-
- There are no concerns whatsoever. The project is in an ideal state to begin building the application logic.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reviews/code_review_2025-11-15_14-30-00.md
DELETED
|
@@ -1,70 +0,0 @@
|
|
| 1 |
-
# Code Review: Cluas MCP
|
| 2 |
-
|
| 3 |
-
**Date:** 2025-11-15
|
| 4 |
-
|
| 5 |
-
## a) High-Level Summary
|
| 6 |
-
|
| 7 |
-
This repository, "Cluas," contains a Python-based project that appears to be a multi-character or multi-agent system for academic research. The name "Cluas" and the character names (Corvus, Raven, Magpie, Crow) all relate to corvids, a family of intelligent birds, suggesting a theme of intelligence and information gathering.
|
| 8 |
-
|
| 9 |
-
The core functionality revolves around searching academic paper databases (arXiv, PubMed, Semantic Scholar) based on user queries. The system is designed with a fallback mechanism, starting with PubMed and progressing to other sources if no results are found. It includes a caching mechanism to speed up repeated searches.
|
| 10 |
-
|
| 11 |
-
The project is structured into several components:
|
| 12 |
-
|
| 13 |
-
- `characters`: Different agents with specific functionalities. So far, only `CorvusMCP` is implemented.
|
| 14 |
-
- `cluas_mcp`: The core logic, including API clients for academic search engines, caching, and data formatting.
|
| 15 |
-
- `gradio`: Suggests a web interface for interacting with the system, though it is currently empty.
|
| 16 |
-
- `tests`: Unit tests for the `CorvusMCP` character, indicating a commitment to testing.
|
| 17 |
-
|
| 18 |
-
## b) Detailed Component Description
|
| 19 |
-
|
| 20 |
-
### `CorvusMCP` Character
|
| 21 |
-
|
| 22 |
-
The `CorvusMCP` class in `src/characters/corvus.py` is the most developed part of the application. Its primary role is to search for academic papers.
|
| 23 |
-
|
| 24 |
-
- **Search Priority:** It follows a clear search strategy: PubMed -> Semantic Scholar -> arXiv. This is a sensible approach, as PubMed is a high-quality, curated database for biomedical literature.
|
| 25 |
-
- **Caching:** It uses a `CacheManager` to store search results. When a search is requested, it first checks the cache for the given query. If found, it returns the cached results, avoiding redundant API calls. If not, it performs the search, and the new results are cached for future use.
|
| 26 |
-
- **API Clients:** It utilizes `PubMedClient`, `SemanticScholarClient`, and `ArxivClient` from `src/cluas_mcp/common/api_clients.py`. Currently, only the `ArxivClient` has a concrete implementation; the others are placeholders.
|
| 27 |
-
- **Data Formatting:** After fetching results, it cleans and formats them into a consistent structure, including title, abstract, authors, publication date, DOI, and a link.
|
| 28 |
-
|
| 29 |
-
### API Clients and Caching
|
| 30 |
-
|
| 31 |
-
- **`api_clients.py`**: This file defines classes for interacting with external academic APIs. The `ArxivClient` is functional and constructs a search query that combines the user's query with a predefined list of keywords related to corvids. This suggests the system has a specialized focus.
|
| 32 |
-
- **`cache.py`**: The `CacheManager` provides a simple file-based JSON cache. It reads and writes to a `cache.json` file, which is effective for a small-scale application.
|
| 33 |
-
|
| 34 |
-
### Testing
|
| 35 |
-
|
| 36 |
-
The `tests/test_corvus.py` file contains unit tests for the `CorvusMCP` class. The tests use `unittest.mock` to patch the API clients and cache manager, allowing for isolated testing of the character's logic. The tests cover several scenarios:
|
| 37 |
-
|
| 38 |
-
- Cache hits.
|
| 39 |
-
- Successful searches with PubMed.
|
| 40 |
-
- Fallback to Semantic Scholar when PubMed returns no results.
|
| 41 |
-
- Fallback to arXiv when both PubMed and Semantic Scholar fail.
|
| 42 |
-
|
| 43 |
-
This demonstrates good software development practices.
|
| 44 |
-
|
| 45 |
-
## c) Opinionated Breakdown and Future Development
|
| 46 |
-
|
| 47 |
-
### What's Good
|
| 48 |
-
|
| 49 |
-
- **Clear Structure:** The project is well-organized, with a logical separation of concerns (characters, core logic, web interface, tests).
|
| 50 |
-
- **Intelligent Design:** The fallback search strategy and caching mechanism are well-thought-out features that improve both the quality of results and the performance of the system.
|
| 51 |
-
- **Thematic Cohesion:** The corvid theme is creative and consistently applied, which can help in building a strong identity for the project.
|
| 52 |
-
- **Test Coverage:** The presence of unit tests for the main character is a great sign of a healthy codebase.
|
| 53 |
-
|
| 54 |
-
### Suggestions for Improvement
|
| 55 |
-
|
| 56 |
-
- **Implement Placeholder Clients:** The `PubMedClient` and `SemanticScholarClient` are currently placeholders. Implementing these would be the highest priority next step to make `CorvusMCP` fully functional.
|
| 57 |
-
- **Expand Character Roles:** The other characters (`Raven`, `Magpie`, `Crow`) are currently empty files. Their roles should be defined and implemented. Based on the `blah.py` file, it seems the intention is for them to have distinct functions:
|
| 58 |
-
- `magpie.find_trending("topic")`: Could focus on identifying popular or recent papers.
|
| 59 |
-
- `raven.get_environmental_data("location")`: Could specialize in a different type of data, perhaps from different sources.
|
| 60 |
-
- `crow.analyze_patterns("dataset")`: Might be geared towards data analysis or trend detection within a set of papers.
|
| 61 |
-
- **Develop the Gradio UI:** The `gradio/app.py` is empty. Building a simple web interface would make the system much more accessible and usable.
|
| 62 |
-
- **Refine the `ArxivClient`:** The `ArxivClient` currently combines the user's query with a hardcoded list of corvid-related keywords. This should be made more flexible, perhaps by allowing the character or user to specify the topic or domain of interest. The `search_academic_papers` function in `tools.py` seems to be a step in this direction.
|
| 63 |
-
- **Configuration Management:** API keys or other configuration settings should not be hardcoded. A configuration file or environment variables should be used.
|
| 64 |
-
- **Error Handling:** The API clients should have more robust error handling for network issues or unexpected API responses.
|
| 65 |
-
|
| 66 |
-
### Future Expectations
|
| 67 |
-
|
| 68 |
-
I expect the project to continue developing by fleshing out the existing structure. The immediate next steps would be to implement the remaining API clients and then define the unique functionalities of the other characters. Once the core logic is more complete, the focus will likely shift to building the Gradio web interface to allow users to interact with the different characters.
|
| 69 |
-
|
| 70 |
-
Overall, this is a promising project with a solid foundation and a clear, creative vision. The code is clean, well-structured, and demonstrates good engineering practices.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reviews/code_review_2025-11-15_15-00-00.md
DELETED
|
@@ -1,62 +0,0 @@
|
|
| 1 |
-
# Code Review: Cluas MCP (Second Pass)
|
| 2 |
-
|
| 3 |
-
**Date:** 2025-11-15
|
| 4 |
-
|
| 5 |
-
## a) High-Level Summary
|
| 6 |
-
|
| 7 |
-
This second review of the "Cluas" repository shows some evolution from the initial version, primarily with the introduction of a shared memory system. The project remains a Python-based, multi-agent framework for academic research, themed around corvids.
|
| 8 |
-
|
| 9 |
-
The core functionality is still centered on the `CorvusMCP` character, which searches academic databases. The most significant change is the replacement of the simple cache with an `AgentMemory` system. This new system is designed to create a shared context between agents by logging discovered items (papers) and allowing retrieval based on recency, tags, or title.
|
| 10 |
-
|
| 11 |
-
The overall structure is largely the same: `characters` for agents, `cluas_mcp` for core logic, a placeholder `gradio` UI, and `tests`. However, many of the previously identified issues, such as placeholder API clients, empty character files, and clutter in the source directory, persist.
|
| 12 |
-
|
| 13 |
-
## b) Detailed Component Description
|
| 14 |
-
|
| 15 |
-
### `CorvusMCP` and `AgentMemory`
|
| 16 |
-
|
| 17 |
-
The `CorvusMCP` character in `src/characters/corvus.py` has been updated to integrate with the new `AgentMemory` system.
|
| 18 |
-
|
| 19 |
-
- **Memory Integration:** Instead of a simple query cache, `CorvusMCP` now interacts with `AgentMemory`. When `search_papers` finds a paper, it logs it as a memory item, tagging it with "academic_search" and noting that "Corvus" mentioned it. This creates a persistent, shared knowledge base.
|
| 20 |
-
- **Contextual Results:** The `search_papers` function now has a `memory_days` parameter. When used, it appends recently mentioned items from the shared memory to the search results. This allows the character to provide contextually aware responses that include not just new findings but also recently discussed topics.
|
| 21 |
-
- **`AgentMemory` Class:** Located in `src/cluas_mcp/common/memory.py`, this class provides a more sophisticated storage mechanism than the previous `CacheManager`. It stores items in a JSON file with structured data, including timestamps, snippets, DOIs, and tags. It supports various retrieval methods:
|
| 22 |
-
- `get_recent(days)`: Fetches items referenced within a specific timeframe.
|
| 23 |
-
- `get_by_tag(tag)`: Retrieves items with a given tag.
|
| 24 |
-
- `search_title(query)`: Performs a simple text search on titles.
|
| 25 |
-
- `prune_long_term()`: A utility to clean up very old memories.
|
| 26 |
-
|
| 27 |
-
### Persisting Issues
|
| 28 |
-
|
| 29 |
-
- **Placeholder API Clients:** The `PubMedClient` and `SemanticScholarClient` in `src/cluas_mcp/common/api_clients.py` are still not implemented. This remains the biggest blocker to the `CorvusMCP`'s full functionality, as it can only search arXiv.
|
| 30 |
-
- **Empty Modules:** The `magpie`, `raven`, and `crow` character files are still empty. The `gradio/app.py` file is also empty, so there is no user-facing interface. The `formatting.py` file is still empty, which means the `corvus.py` file is still broken.
|
| 31 |
-
- **Cluttered Source Directory:** The `src/cluas_mcp` directory still contains scripts that appear to be for testing or experimentation (`abstract_filtered.py`, `testing_arxiv.py`, `blah.py`).
|
| 32 |
-
- **Lack of Tests for New Functionality:** There are no new tests for the `AgentMemory` class or for the updated `CorvusMCP` that uses it. The existing test files are either empty or haven't been updated.
|
| 33 |
-
|
| 34 |
-
## c) Opinionated Breakdown and Future Development
|
| 35 |
-
|
| 36 |
-
### What's Good
|
| 37 |
-
|
| 38 |
-
- **Shared Memory is a Strong Concept:** The introduction of `AgentMemory` is a significant conceptual improvement. It moves the system from a simple tool to a collaborative multi-agent system where agents can build on each other's findings. This is a much more interesting and powerful architecture.
|
| 39 |
-
- **Improved `CorvusMCP` Logic:** The ability to include recent memories in search results is a smart feature that makes the agent more context-aware.
|
| 40 |
-
|
| 41 |
-
### Room for Improvement
|
| 42 |
-
|
| 43 |
-
The project is still in a conceptual phase, and the execution is lagging behind the ideas. The critical feedback from the previous review still applies:
|
| 44 |
-
|
| 45 |
-
1. **Fix the Broken Code:** The `formatting.py` file needs to be implemented so that `corvus.py` can run. This is the most immediate and critical issue.
|
| 46 |
-
2. **Implement the API Clients:** The `PubMedClient` and `SemanticScholarClient` must be implemented for the core feature to work as designed.
|
| 47 |
-
3. **Write Tests for `AgentMemory`:** The new memory system is a critical component and should be thoroughly tested. Tests for adding, retrieving, and pruning items are essential.
|
| 48 |
-
4. **Clean the `src` Directory:** The experimental scripts should be moved out of the main source directory to improve code hygiene.
|
| 49 |
-
5. **Define Other Agent Roles:** The vision for the other agents (`Magpie`, `Raven`, `Crow`) should be translated into code. What do they do? How do they interact with the shared memory? For example:
|
| 50 |
-
- `Magpie` could search for trending topics on social media or news sites and add them to memory with a "trending" tag.
|
| 51 |
-
- `Raven` could be tasked with a specific, long-term monitoring goal, periodically updating a set of memory items.
|
| 52 |
-
6. **Build the UI:** A simple Gradio interface would provide a much-needed way to interact with the agents and see the shared memory in action.
|
| 53 |
-
|
| 54 |
-
### Future Expectations
|
| 55 |
-
|
| 56 |
-
The introduction of `AgentMemory` sets a clear direction for the project. The focus should now be on building out the ecosystem around this shared memory. I expect the next phase of development to involve:
|
| 57 |
-
|
| 58 |
-
- Making the existing `CorvusMCP` character fully functional by implementing the remaining API clients.
|
| 59 |
-
- Adding at least one more character with a distinct role that reads from or writes to the `AgentMemory`.
|
| 60 |
-
- Adding a basic user interface to demonstrate the multi-agent interaction.
|
| 61 |
-
|
| 62 |
-
The project has a stronger conceptual foundation now, but it needs a significant implementation effort to realize its potential. The priority should be to make the existing code runnable and tested before adding more features.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reviews/code_review_2025-11-15_15-30-00.md
DELETED
|
@@ -1,62 +0,0 @@
|
|
| 1 |
-
# Code Review: Corvid Council (Third Pass)
|
| 2 |
-
|
| 3 |
-
**Date:** 2025-11-15
|
| 4 |
-
|
| 5 |
-
## a) High-Level Summary
|
| 6 |
-
|
| 7 |
-
This review assesses the "Cluas" repository against the detailed "Corvid Council - Development Guide." The document clarifies that the project is a multi-agent system ("Corvid Council") for a hackathon, with a clear vision, architecture, and development plan. The goal is a Gradio-based group chat of four AI crow experts (Corvus, Magpie, Raven, Crow) that also exposes its functionality as a set of external MCP tools.
|
| 8 |
-
|
| 9 |
-
The current codebase represents a very early stage of this vision. It has established a foundational piece of the `Corvus` character and the `AgentMemory` system, which aligns with the "Week 1: Days 1-2" goals of the development plan. However, the implementation is still far from the complete architecture described in the guide. The existing code provides a skeleton for one character's tools but does not yet include the orchestration, multi-agent interaction, or the dual Gradio/MCP interface that are central to the project concept.
|
| 10 |
-
|
| 11 |
-
## b) Detailed Description of Components vs. Project Plan
|
| 12 |
-
|
| 13 |
-
### Current Implementation vs. "Week 1: Days 1-2" Goals
|
| 14 |
-
|
| 15 |
-
The development guide sets a clear goal for the first two days: "One character working with tools in Gradio." Let's see how the current code stacks up.
|
| 16 |
-
|
| 17 |
-
- **`Corvus` Character:** The `src/characters/corvus.py` file lays the groundwork for the "Scholar" archetype. Its `search_papers` function, with its fallback logic (PubMed -> Semantic Scholar -> arXiv), aligns perfectly with the described perfectionist, citation-focused personality. The integration with `AgentMemory` to log findings is a direct implementation of the cross-agent context recall mentioned in the guide.
|
| 18 |
-
- **`AgentMemory`:** The `src/cluas_mcp/common/memory.py` is a solid first pass at the "agent-memory subsystem." It supports adding items with metadata (`mentioned_by`, `tags`) and retrieving them, which is the core requirement for enabling cross-agent context.
|
| 19 |
-
- **API Clients:** The `src/cluas_mcp/common/api_clients.py` file contains the stubs for the clients Corvus needs. The `ArxivClient` is functional, which allows for some level of testing, while the others are placeholders. This is consistent with the iterative approach of getting one part working first.
|
| 20 |
-
- **Missing Components:** Crucially, several key components from the development guide are entirely absent from the current codebase:
|
| 21 |
-
- **`CouncilOrchestrator`**: There is no orchestrator to manage conversation flow or facilitate discussion between agents.
|
| 22 |
-
- **`Character` Base Class**: The `CorvusMCP` class is standalone; it does not inherit from a common `Character` base class.
|
| 23 |
-
- **Gradio Interface**: The `gradio/app.py` is empty. There is no UI to interact with Corvus.
|
| 24 |
-
- **MCP Tool Exposure**: There is no code to expose the `ask_crow_council` or other external MCP tools.
|
| 25 |
-
|
| 26 |
-
In summary, the current code has started implementing the `Corvus` character's internal logic but has not yet built the framework (orchestrator, base classes, UI) that will allow it to function as part of the "Corvid Council."
|
| 27 |
-
|
| 28 |
-
## c) Opinionated Breakdown, Expectations, and Suggestions
|
| 29 |
-
|
| 30 |
-
The development guide is excellent and provides a clear roadmap. The "roughness" of the current code is perfectly understandable in this context. The focus has clearly been on prototyping a single agent's core behavior, which is a sensible way to start.
|
| 31 |
-
|
| 32 |
-
### Alignment with Vision
|
| 33 |
-
|
| 34 |
-
- **Good:** The `CorvusMCP` and `AgentMemory` components are well-aligned with the project's vision. The idea of logging findings to a shared memory is a strong foundation for the multi-agent system.
|
| 35 |
-
- **Gap:** The current file structure does not match the target structure outlined in the guide. For example, the tools are not yet separated into `src/mcp/tools/`, and there is no `orchestrator.py` or `character.py`.
|
| 36 |
-
|
| 37 |
-
### Actionable Suggestions for Next Steps
|
| 38 |
-
|
| 39 |
-
Given the detailed plan, my suggestions are to follow it closely. Here is a prioritized list of actions to bridge the gap between the current code and the "Week 1" goals:
|
| 40 |
-
|
| 41 |
-
1. **Establish the Target File Structure:** Before writing more code, refactor the existing files to match the structure in the development guide. This will make the project much easier to navigate and build upon.
|
| 42 |
-
- Create `src/orchestrator.py`, `src/character.py`, and `src/mcp/tools/academic.py`.
|
| 43 |
-
- Move the `CorvusMCP` logic into `src/characters/corvus.py` and make it inherit from a new `Character` base class in `src/character.py`.
|
| 44 |
-
- Move the API client logic into the appropriate tool files (e.g., `academic.py`).
|
| 45 |
-
- Move the experimental scripts (`blah.py`, etc.) to an `/experimental` directory as planned.
|
| 46 |
-
|
| 47 |
-
2. **Implement the `CouncilOrchestrator` Skeleton:** Create the `CouncilOrchestrator` class with placeholder methods as described in the guide. This will be the central hub of the application.
|
| 48 |
-
|
| 49 |
-
3. **Build a Basic Gradio UI:** Implement a minimal version of the Gradio interface. The goal for "Days 1-2" is to be able to ask a question and see Corvus respond. This will involve:
|
| 50 |
-
- Creating the chat UI in `src/ui/interface.py`.
|
| 51 |
-
- Wiring the UI to the `CouncilOrchestrator`.
|
| 52 |
-
- Having the orchestrator call the `Corvus` character.
|
| 53 |
-
|
| 54 |
-
4. **Fix the Broken Import:** The `formatting.py` file is still empty, which blocks `CorvusMCP` from running. Implement the `snippet_abstract` and `format_authors` functions so the character's output can be displayed.
|
| 55 |
-
|
| 56 |
-
5. **Write Tests:** As you build these components, write basic unit tests as planned. A test for the `AgentMemory` and a simple integration test for the orchestrator calling Corvus would be a great start.
|
| 57 |
-
|
| 58 |
-
### Future Expectations
|
| 59 |
-
|
| 60 |
-
Following the development guide, I expect to see the project evolve rapidly. After establishing the core framework and getting Corvus to respond in the UI, the next logical steps will be to add the `Magpie` character and implement the staggered, interactive conversation flow described in the guide.
|
| 61 |
-
|
| 62 |
-
The project is ambitious for a hackathon, but the detailed plan makes it achievable. The key will be to follow the phased approach, ensuring each component is functional before moving to the next. The current code is a good, albeit small, first step on that path.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reviews/code_review_2025-11-15_16-00-00.md
DELETED
|
@@ -1,37 +0,0 @@
|
|
| 1 |
-
# Code Review: Corvid Council (Fourth Pass)
|
| 2 |
-
|
| 3 |
-
**Date:** 2025-11-15
|
| 4 |
-
|
| 5 |
-
## a) High-Level Summary
|
| 6 |
-
|
| 7 |
-
This review covers the latest changes to the "Corvid Council" repository, which are primarily administrative and structural. The updates focus on preparing the project for deployment on Hugging Face Spaces and aligning the repository with standard Python project practices.
|
| 8 |
-
|
| 9 |
-
Key changes include the addition of a `README.md`, a `.gitignore` file, and a `requirements.txt` file. The `README.md` now effectively serves as the project's development guide, formalizing the vision and architecture. A placeholder Gradio application has also been added. While there are no major changes to the core agent logic, these updates represent a significant step towards professionalizing the repository and making it ready for collaborative development and deployment.
|
| 10 |
-
|
| 11 |
-
## b) Detailed Description of Changes
|
| 12 |
-
|
| 13 |
-
- **`README.md`:** The repository now has a comprehensive `README.md` file. It is a copy of the "Corvid Council - Development Guide," which clearly outlines the project's concept, architecture, character archetypes, and development plan. This is an excellent addition that makes the project's goals clear to any new contributor.
|
| 14 |
-
- **`requirements.txt`:** A `requirements.txt` file has been added, listing the project's dependencies: `feedparser`, `requests`, `gradio`, and `huggingface_hub`. This is essential for ensuring a reproducible environment, especially for deployment on Hugging Face Spaces.
|
| 15 |
-
- **`.gitignore`:** A standard Python `.gitignore` file has been included. This is a crucial piece of repository hygiene that prevents unnecessary files (like `__pycache__`, `.env`, virtual environment folders) from being committed to version control. It also correctly ignores the `cache.json` and `memory.json` files.
|
| 16 |
-
- **`src/gradio/app.py`:** A basic Gradio application has been added. It currently contains boilerplate code for a `ChatInterface` that connects to an OpenAI model on the Hugging Face Hub. It is not yet integrated with the Corvid Council agents, but it provides the entry point for building the user-facing UI.
|
| 17 |
-
- **No Core Logic Changes:** The core logic in `src/characters/corvus.py` and `src/cluas_mcp/common/memory.py` remains unchanged from the previous review.
|
| 18 |
-
|
| 19 |
-
## c) Opinionated Breakdown and Suggestions
|
| 20 |
-
|
| 21 |
-
These administrative changes were much-needed and have significantly improved the project's structure and readiness. While not feature development, this work is critical for a healthy project.
|
| 22 |
-
|
| 23 |
-
### What's Good
|
| 24 |
-
|
| 25 |
-
- **Excellent Documentation:** The `README.md` is now the project's single source of truth for its vision and plan. This is a best practice that was correctly prioritized.
|
| 26 |
-
- **Ready for Deployment:** With `requirements.txt` and a basic `app.py`, the project is now technically deployable to Hugging Face Spaces, which is a key part of the hackathon plan.
|
| 27 |
-
- **Improved Repository Hygiene:** The `.gitignore` file cleans up the repository and prevents common issues with sensitive data or unnecessary files in version control.
|
| 28 |
-
|
| 29 |
-
### Suggestions for Next Steps
|
| 30 |
-
|
| 31 |
-
The project is now well-positioned to continue with the "Week 1" development plan. The next steps should be to:
|
| 32 |
-
|
| 33 |
-
1. **Integrate the Core Logic with Gradio:** The immediate priority is to replace the boilerplate `respond` function in `src/gradio/app.py` with the logic from the `CouncilOrchestrator` (which still needs to be created). The goal is to have user input from the Gradio interface trigger the `Corvus` character's `search_papers` method.
|
| 34 |
-
2. **Continue the Refactoring:** As suggested in the previous review, continue refactoring the code to match the target file structure outlined in the `README.md`. This will involve creating the `CouncilOrchestrator` and the `Character` base class.
|
| 35 |
-
3. **Fix the `formatting.py` file:** This remains a blocker. The `snippet_abstract` and `format_authors` functions need to be implemented for the `Corvus` character to work.
|
| 36 |
-
|
| 37 |
-
This round of changes was a successful and necessary step in maturing the project. The focus can now shift back to implementing the core features on this much stronger foundation.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reviews/code_review_2025-11-18_10-00-00.md
DELETED
|
@@ -1,61 +0,0 @@
|
|
| 1 |
-
# Code Review: Corvid Council - Initial Scaffolding
|
| 2 |
-
|
| 3 |
-
**Date:** 2025-11-18
|
| 4 |
-
|
| 5 |
-
## a) High-Level Summary
|
| 6 |
-
|
| 7 |
-
The Corvid Council project is in its nascent stages, with the foundational scaffolding for a multi-agent research system. The core concept is strong: a group of specialized AI agents collaborating to research and discuss topics, retaining knowledge over time in a shared memory. The initial code sets up a key character, `Corvus`, responsible for academic searches, and a crucial `AgentMemory` component for persistence. However, the project is not yet functional due to missing implementations and architectural gaps. The immediate blockers are broken imports and placeholder API clients, which prevent the `Corvus` agent from executing its primary function.
|
| 8 |
-
|
| 9 |
-
## b) Detailed Component Description
|
| 10 |
-
|
| 11 |
-
### `src/characters/corvus.py`
|
| 12 |
-
|
| 13 |
-
This file defines the `CorvusMCP` class, the first of the AI agents.
|
| 14 |
-
|
| 15 |
-
* **Functionality:** Its main purpose is to `search_papers` across multiple academic databases (PubMed, Semantic Scholar, arXiv) in a fallback sequence.
|
| 16 |
-
* **Integration:** It correctly initializes and uses the `AgentMemory` system by logging every paper it finds. This is a good early integration, ensuring that the agent's "discoveries" contribute to the collective knowledge base.
|
| 17 |
-
* **Issue:** The tool is currently broken. It imports `format_authors` and `snippet_abstract` from `src/cluas_mcp/common/formatting.py`, which is an empty file. This will cause a runtime `ImportError`.
|
| 18 |
-
* **Structure:** The class is straightforward, but it could benefit from being derived from a common `Character` base class in the future to standardize agent interfaces.
|
| 19 |
-
|
| 20 |
-
### `src/cluas_mcp/common/memory.py`
|
| 21 |
-
|
| 22 |
-
This is arguably the most complete and well-realized component so far.
|
| 23 |
-
|
| 24 |
-
* **Functionality:** The `AgentMemory` class provides a simple but effective JSON-backed database for the agents. It allows adding items, retrieving them based on recency or tags, and searching by title.
|
| 25 |
-
* **Persistence:** It handles file I/O for reading and writing to a `memory.json` file, ensuring that the council's knowledge persists between sessions.
|
| 26 |
-
* **Design:** The use of a dictionary with lowercase titles as keys is a simple but effective way to avoid duplicate entries and update reference timestamps. The methods for adding, retrieving, and searching are clear and well-defined.
|
| 27 |
-
|
| 28 |
-
### `src/gradio/app.py`
|
| 29 |
-
|
| 30 |
-
This file contains a boilerplate Gradio `ChatInterface`.
|
| 31 |
-
|
| 32 |
-
* **Functionality:** It sets up a basic chat window and connects it to the Hugging Face Inference API.
|
| 33 |
-
* **Issue:** It is completely disconnected from the Corvid Council agent system. The `respond` function is a generic chatbot implementation and does not interact with `Corvus` or the `AgentMemory`. This is expected at this early stage but is a key area for future development.
|
| 34 |
-
|
| 35 |
-
## c) Opinionated Breakdown & Future Development
|
| 36 |
-
|
| 37 |
-
### Current State
|
| 38 |
-
|
| 39 |
-
The project has a good foundation but is more of an idea sketched in code than a working system. The separation of concerns is logical (characters, common utilities, UI), and the `AgentMemory` component is a solid start.
|
| 40 |
-
|
| 41 |
-
The most significant issue is the lack of a central orchestrator. There is no "council," only a single, non-functional agent. The project's `README.md` and `gemini.md` files clearly outline a vision that the code has not yet begun to implement.
|
| 42 |
-
|
| 43 |
-
### Suggestions for Future Development
|
| 44 |
-
|
| 45 |
-
1. **Fix the `Corvus` Agent:** The immediate priority is to implement the missing functions in `formatting.py` (`format_authors` and `snippet_abstract`). These could be simple implementations to start (e.g., `", ".join(authors)` and `abstract[:250] + "..."`).
|
| 46 |
-
|
| 47 |
-
2. **Implement API Clients:** The `gemini.md` file notes that the API clients are stubs. These need to be implemented to make `Corvus` functional. This involves writing the logic to make actual HTTP requests to PubMed, Semantic Scholar, and arXiv and parse their responses.
|
| 48 |
-
|
| 49 |
-
3. **Create a `CouncilOrchestrator`:** This is the most critical missing piece. A central class is needed to:
|
| 50 |
-
* Manage the roster of agents (Corvus, Magpie, etc.).
|
| 51 |
-
* Receive a user's query.
|
| 52 |
-
* Mediate the conversation between agents (e.g., pass the query to Corvus, then pass Corvus's findings to another agent for critique).
|
| 53 |
-
* Synthesize the final response for the user.
|
| 54 |
-
|
| 55 |
-
4. **Develop a `Character` Base Class:** To ensure all agents have a consistent interface, a `Character` abstract base class would be beneficial. It could define a common method like `process_query(query: str, context: List[str]) -> str` that each specialized agent would implement.
|
| 56 |
-
|
| 57 |
-
5. **Integrate Logic with Gradio UI:** Once the orchestrator is in place, the `respond` function in `gradio/app.py` should be rewritten to call the orchestrator instead of the generic Inference API. The chat history would represent the ongoing discussion of the council.
|
| 58 |
-
|
| 59 |
-
6. **Flesh out Other Characters:** After establishing the core architecture, the other characters (Magpie, Raven, Crow) can be created, each with their own specialized tools and "personalities."
|
| 60 |
-
|
| 61 |
-
In summary, the project has a promising conceptual foundation. The next steps should focus on building the core architectural components that will allow the agents to interact and turning the placeholder code into functional modules.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reviews/code_review_2025-11-18_10-30-00.md
DELETED
|
@@ -1,50 +0,0 @@
|
|
| 1 |
-
# Code Review: Corvid Council - Path to Functionality
|
| 2 |
-
|
| 3 |
-
**Date:** 2025-11-18
|
| 4 |
-
|
| 5 |
-
## a) High-Level Summary
|
| 6 |
-
|
| 7 |
-
The Corvid Council project has made a significant leap forward from a conceptual skeleton to a project with a clear and actionable roadmap. The addition of comprehensive development guides (`notes_etc/`) provides an excellent framework for the project's architecture, agent design, and phased implementation. Most importantly, a critical bug has been fixed by implementing the functions in `src/cluas_mcp/common/formatting.py`, which unblocks the `Corvus` agent. While the system is not yet fully operational (pending API client implementations and an orchestrator), it has moved from a state of being blocked to having a clear path toward achieving its "Week 1" goals.
|
| 8 |
-
|
| 9 |
-
## b) Detailed Component Description
|
| 10 |
-
|
| 11 |
-
### `notes_etc/development_guide_01.md`
|
| 12 |
-
|
| 13 |
-
This new document is the most important addition to the repository. It serves as the project's bible.
|
| 14 |
-
|
| 15 |
-
* **Content:** It lays out the entire vision, from the high-level concept and architecture to the specific personalities and toolsets of the four agents (Corvus, Magpie, Raven, Crow). It also defines the external MCP tools the app will expose, the core software components (`CouncilOrchestrator`, `Character` base class), and a detailed week-by-week development plan.
|
| 16 |
-
* **Impact:** This guide provides invaluable clarity. It solidifies the project's goals and gives a strong indication of the intended structure, which was previously only hinted at in the `README.md`. It's an excellent piece of planning documentation.
|
| 17 |
-
|
| 18 |
-
### `src/cluas_mcp/common/formatting.py`
|
| 19 |
-
|
| 20 |
-
This file has been changed from an empty placeholder to a functional module.
|
| 21 |
-
|
| 22 |
-
* **Functionality:** It now contains `snippet_abstract` and `format_authors`. These functions provide basic but sensible text formatting, ensuring that data retrieved by agents can be presented cleanly.
|
| 23 |
-
* **Impact:** This is a critical fix. It resolves the `ImportError` that previously prevented the `CorvusMCP` tool from running. The `Corvus` agent, while still dependent on placeholder API clients, is now executable.
|
| 24 |
-
|
| 25 |
-
### `src/characters/corvus.py`
|
| 26 |
-
|
| 27 |
-
The `Corvus` agent is now in a much better state due to the fix in `formatting.py`.
|
| 28 |
-
|
| 29 |
-
* **State:** The code is unchanged, but its context has changed. It can now successfully call the formatting functions.
|
| 30 |
-
* **Next Blocker:** The primary blocker for `Corvus` is now the placeholder API clients (`PubMedClient`, `SemanticScholarClient`, etc.) defined in `src/cluas_mcp/common/api_clients.py`. Until these are implemented to make real API calls, `Corvus` cannot retrieve any data.
|
| 31 |
-
|
| 32 |
-
## c) Opinionated Breakdown & Future Development
|
| 33 |
-
|
| 34 |
-
### Current State
|
| 35 |
-
|
| 36 |
-
The project is now on solid ground. The combination of a detailed plan and a critical bug fix has transformed it from a collection of disconnected files into a project with a clear trajectory. The immediate blockers are well-defined, and the long-term vision is compelling. The core challenge remains the same: building the central nervous system of the application—the `CouncilOrchestrator`—and connecting it to the agents and the UI.
|
| 37 |
-
|
| 38 |
-
### Suggestions for Future Development
|
| 39 |
-
|
| 40 |
-
The development plan laid out in `notes_etc/development_guide_01.md` is excellent and should be followed closely. My suggestions are aligned with it:
|
| 41 |
-
|
| 42 |
-
1. **Implement API Clients:** The immediate next step must be to implement the real API call logic in `src/cluas_mcp/common/api_clients.py`. Start with one (e.g., `PubMedClient` or `ArxivClient`) to get `Corvus` working end-to-end, even if it's just one data source.
|
| 43 |
-
|
| 44 |
-
2. **Build the `CouncilOrchestrator` Skeleton:** As per the guide, create `src/orchestrator.py`. It doesn't need to be fully featured at first. A simple version that can take a query, pass it to the `Corvus` agent, and get a result would be a huge step forward.
|
| 45 |
-
|
| 46 |
-
3. **Create the `Character` Base Class:** Create the `src/character.py` file with an abstract base class. Refactor `CorvusMCP` to inherit from this class. This will establish a pattern that will make adding the other three agents much easier.
|
| 47 |
-
|
| 48 |
-
4. **Basic UI Integration:** Wire the `CouncilOrchestrator` to the Gradio UI. The `respond` function in `src/gradio/app.py` should be updated to call `orchestrator.process_query(message)`. This will achieve the "Day 1-2" goal from the development guide: "Ask 'Are crows smart?', see Corvus search papers and respond with citation."
|
| 49 |
-
|
| 50 |
-
The project is well-positioned for rapid progress. By focusing on the "Week 1" goals from the new development guide, the core functionality of a single-agent system can be achieved quickly, providing a solid foundation for the more complex multi-agent interactions to come.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reviews/code_review_2025-11-18_16-00-00.md
DELETED
|
@@ -1,42 +0,0 @@
|
|
| 1 |
-
# Code Review: Corvid Council - Implementation Begins
|
| 2 |
-
|
| 3 |
-
**Date:** 2025-11-18
|
| 4 |
-
|
| 5 |
-
## a) High-Level Summary
|
| 6 |
-
|
| 7 |
-
The project has successfully transitioned from planning and bug-fixing to active feature development. The most critical blocker—the lack of functional API clients—is being directly addressed. The `ArxivClient` is now fully implemented, and the `PubMedClient` is halfway there. This marks a significant turning point for the project, as the `Corvus` agent now has access to real, structured data from at least one source. While the overall architecture (orchestrator, character base class) is still missing, this concrete progress on the data layer is a crucial and encouraging step towards a functional application.
|
| 8 |
-
|
| 9 |
-
## b) Detailed Component Description
|
| 10 |
-
|
| 11 |
-
### `src/cluas_mcp/common/api_clients.py`
|
| 12 |
-
|
| 13 |
-
This file is now the center of the project's momentum. It has evolved from a collection of placeholders and comments into a partially functional module.
|
| 14 |
-
|
| 15 |
-
* **`ArxivClient`:** This class is now fully implemented and serves as a great template for the other clients. It correctly formulates a URL for the arXiv API, uses `requests` to get the data, and then uses the `feedparser` library to parse the resulting Atom XML feed. It demonstrates a complete, end-to-end data retrieval process: query -> fetch -> parse -> structure.
|
| 16 |
-
|
| 17 |
-
* **`PubMedClient`:** This class has seen significant progress.
|
| 18 |
-
* The `pubmed_search` method implements the first half of the required two-step process. It intelligently constructs a search term from keywords and uses the `esearch.fcgi` endpoint to retrieve a list of article IDs.
|
| 19 |
-
* The `parse_id_list` helper method correctly uses `xml.etree.ElementTree` to parse the XML response and extract the IDs.
|
| 20 |
-
* **Missing Piece:** The client still needs an `efetch` method to take these IDs and retrieve the full article details.
|
| 21 |
-
|
| 22 |
-
* **`SemanticScholarClient`:** This remains a placeholder and is the last remaining data source to be implemented for the `Corvus` agent.
|
| 23 |
-
|
| 24 |
-
## c) Opinionated Breakdown & Future Development
|
| 25 |
-
|
| 26 |
-
### Current State
|
| 27 |
-
|
| 28 |
-
This is the most positive review yet. The "brutal" assessment from our last exchange has been met with direct action. The project is no longer just a collection of plans; it has a working data pipeline for one of its key components. This is a classic example of "bottom-up" implementation: building the foundational data layers first before wiring them into the higher-level application logic.
|
| 29 |
-
|
| 30 |
-
The `Corvus` agent is now theoretically capable of searching arXiv, which is a major milestone. The immediate next steps are very clear and build directly on the work that has just been completed.
|
| 31 |
-
|
| 32 |
-
### Suggestions for Future Development
|
| 33 |
-
|
| 34 |
-
1. **Complete the `PubMedClient`:** The highest priority is to finish what was started. Create a new method, perhaps `fetch_paper_details(ids: List[str])`, that takes the output from `pubmed_search`, calls the `efetch.fcgi` endpoint, and parses the resulting XML to extract the title, abstract, authors, and DOI for each paper. This will bring the `PubMedClient` to parity with the `ArxivClient`.
|
| 35 |
-
|
| 36 |
-
2. **Refactor `corvus.py`:** Modify the `CorvusMCP.search_papers` method to use the newly implemented clients. The fallback logic (`try PubMed -> fallback to arXiv`) can now be implemented with real function calls. This will make the `Corvus` agent fully data-functional.
|
| 37 |
-
|
| 38 |
-
3. **Implement `SemanticScholarClient`:** Tackle the final placeholder client to complete the data-gathering capabilities of `Corvus`.
|
| 39 |
-
|
| 40 |
-
4. **Shift Focus to the Orchestrator:** Once `Corvus` is fully functional, the focus must shift to the application layer. It's time to create the `CouncilOrchestrator` and the `Character` base class as outlined in the development guides. The goal should be to create the simplest possible loop: a query comes in, the orchestrator passes it to `Corvus`, `Corvus` uses its new tools to get real data, and the result is printed or returned.
|
| 41 |
-
|
| 42 |
-
The project has gained significant momentum. The key is to maintain it by immediately building on this success to complete the data layer and then moving up the stack to the application logic.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reviews/code_review_2025-11-18_17-00-00.md
DELETED
|
@@ -1,52 +0,0 @@
|
|
| 1 |
-
# Code Review: Corvid Council - A Move Towards Robustness
|
| 2 |
-
|
| 3 |
-
**Date:** 2025-11-18
|
| 4 |
-
|
| 5 |
-
## a) High-Level Summary
|
| 6 |
-
|
| 7 |
-
The project has undergone a significant and positive architectural refactoring. The creation of a dedicated `academic` submodule for the `PubMedClient` and the introduction of a shared, resilient HTTP utility (`common/http.py`) show a clear move towards building a more organized, maintainable, and robust application. This addresses not just functionality but also code quality and long-term health. However, this refactoring is incomplete, having introduced significant code duplication that must be resolved.
|
| 8 |
-
|
| 9 |
-
## b) Detailed Component Description
|
| 10 |
-
|
| 11 |
-
### `src/cluas_mcp/common/http.py`
|
| 12 |
-
|
| 13 |
-
This new file is a major architectural improvement.
|
| 14 |
-
|
| 15 |
-
* **Functionality:** It provides a `fetch_with_retry` function that wraps `requests.get` with a sophisticated retry mechanism using the `tenacity` library. It correctly implements exponential backoff and is configured to retry on transient HTTP errors (5xx status codes) and rate-limiting responses (HTTP 429), which is crucial for consuming public APIs.
|
| 16 |
-
* **Impact:** This utility makes the entire system more resilient. By centralizing this logic, any API client that uses it automatically becomes more robust without duplicating code.
|
| 17 |
-
|
| 18 |
-
### `src/cluas_mcp/academic/pubmed_client.py`
|
| 19 |
-
|
| 20 |
-
This new file represents a structural improvement, aligning the codebase with the planned architecture.
|
| 21 |
-
|
| 22 |
-
* **Functionality:** It contains the `PubMedClient` and its `pubmed_search` method, which is responsible for querying the PubMed `esearch` endpoint.
|
| 23 |
-
* **Improvement:** It has been updated to use the new `fetch_with_retry` function, immediately benefiting from the added resilience.
|
| 24 |
-
|
| 25 |
-
### `src/cluas_mcp/common/api_clients.py`
|
| 26 |
-
|
| 27 |
-
This file is now a source of technical debt.
|
| 28 |
-
|
| 29 |
-
* **State:** It still contains the old `PubMedClient` implementation, which is now obsolete. The `ArxivClient` and the placeholder `SemanticScholarClient` also remain here.
|
| 30 |
-
* **Problem:** The presence of the old `PubMedClient` creates direct code duplication. It's unclear to a new developer which client is the correct one to use, and imports could easily point to the wrong one.
|
| 31 |
-
|
| 32 |
-
## c) Opinionated Breakdown & Future Development
|
| 33 |
-
|
| 34 |
-
### Current State
|
| 35 |
-
|
| 36 |
-
The project is in a state of healthy, if incomplete, transition. The decision to refactor the API clients into separate modules and create a shared HTTP utility is excellent. It shows that the developer is thinking not just about "what" the code does, but "how" it should be structured for maintainability.
|
| 37 |
-
|
| 38 |
-
However, the job is only half-done. The lingering code duplication in `api_clients.py` is a significant problem that negates some of the benefits of the refactoring. It's a textbook example of technical debt that should be paid down immediately before it causes problems.
|
| 39 |
-
|
| 40 |
-
### Suggestions for Future Development
|
| 41 |
-
|
| 42 |
-
1. **Complete the Refactoring (Immediate Priority):**
|
| 43 |
-
* **Delete the old `PubMedClient`** from `src/cluas_mcp/common/api_clients.py`.
|
| 44 |
-
* **Move the `ArxivClient`** from `api_clients.py` to a new file: `src/cluas_mcp/academic/arxiv_client.py`. Update it to use the `fetch_with_retry` function as well.
|
| 45 |
-
* **Move the `SemanticScholarClient`** placeholder to `src/cluas_mcp/academic/semantic_scholar_client.py`.
|
| 46 |
-
* **Delete the `api_clients.py` file** entirely, as its purpose has been superseded by the new `academic` submodule.
|
| 47 |
-
|
| 48 |
-
2. **Complete the `PubMedClient` Functionality:** Once the refactoring is clean, return to implementing the `efetch` logic in `src/cluas_mcp/academic/pubmed_client.py`. Create the method that takes the list of IDs and fetches the full paper details.
|
| 49 |
-
|
| 50 |
-
3. **Update `corvus.py` Imports:** After the refactoring, the `import` statements at the top of `src/characters/corvus.py` will be broken. They will need to be updated to point to the new locations of the client classes (e.g., `from ..cluas_mcp.academic.pubmed_client import PubMedClient`).
|
| 51 |
-
|
| 52 |
-
The project is making great strides in code quality. The immediate task is to complete the cleanup from this recent refactoring to solidify the architectural gains before moving on to the next feature.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reviews/code_review_2025-11-18_18-00-00.md
DELETED
|
@@ -1,55 +0,0 @@
|
|
| 1 |
-
# Code Review: Corvid Council - A Milestone Achieved
|
| 2 |
-
|
| 3 |
-
**Date:** 2025-11-18
|
| 4 |
-
|
| 5 |
-
## a) High-Level Summary
|
| 6 |
-
|
| 7 |
-
The project has undergone a transformative set of changes, evolving from a scattered collection of scripts into a well-structured, tested, and robust data access layer. The previous architectural issues have been fully addressed through a major refactoring. The API clients are now modular, the `PubMedClient` is feature-complete, and the entire system is supported by a resilient HTTP utility. Most importantly, the addition of a test suite marks a pivotal moment in the project's lifecycle, providing a foundation for reliable and scalable development. The data-gathering toolkit for the `Corvus` agent is now effectively complete.
|
| 8 |
-
|
| 9 |
-
## b) Detailed Component Description
|
| 10 |
-
|
| 11 |
-
### `src/cluas_mcp/academic/` (Submodule)
|
| 12 |
-
|
| 13 |
-
This new submodule is the heart of the recent changes and represents the project's data access layer.
|
| 14 |
-
|
| 15 |
-
* **`pubmed.py` & `arxiv.py`:** These files contain the clean, refactored, and feature-complete clients for their respective services. They are focused, easy to understand, and leverage the shared `http.py` utility. The `PubMedClient` now correctly implements the full `esearch` -> `efetch` workflow.
|
| 16 |
-
* **`academic_search.py`:** This file introduces the "Facade" design pattern to the project. The `academic_search` function provides a single, simple interface for querying all underlying academic sources. This decouples the agent logic from the specifics of each API client, which is an excellent architectural choice that will make the `Corvus` agent much simpler to implement.
|
| 17 |
-
|
| 18 |
-
### `src/cluas_mcp/domain/` (Submodule)
|
| 19 |
-
|
| 20 |
-
* **`keywords.py`:** The creation of this submodule to hold domain-specific data (like lists of corvid-related keywords) is a sign of a maturing codebase. It properly separates data from logic, making the system easier to configure and maintain.
|
| 21 |
-
|
| 22 |
-
### `tests/` (Directory)
|
| 23 |
-
|
| 24 |
-
The addition of `test_arxiv.py` and `test_pubmed.py` is the most significant improvement in this round of changes.
|
| 25 |
-
|
| 26 |
-
* **Functionality:** These files provide simple but effective integration tests for the API clients. They make real calls to the APIs and perform basic validation on the results.
|
| 27 |
-
* **Impact:** This is a critical best practice. These tests ensure that the data sources—the very foundation of the application—are working as expected. They prevent regressions and provide confidence for future modifications.
|
| 28 |
-
|
| 29 |
-
## c) Opinionated Breakdown & Future Development
|
| 30 |
-
|
| 31 |
-
### Current State
|
| 32 |
-
|
| 33 |
-
The project is now in an excellent state. The "brutal" feedback from earlier has been met with a flurry of high-quality work that has not only fixed the identified problems but has exceeded expectations by introducing tests and better architectural patterns. The technical debt from the initial exploratory phase has been paid down, and the foundation is now solid.
|
| 34 |
-
|
| 35 |
-
The `Corvus` agent has a complete, robust, and tested toolkit at its disposal. The project has successfully completed the "build the data layer" phase and is now perfectly positioned to move up the stack to the application logic.
|
| 36 |
-
|
| 37 |
-
### Suggestions for Future Development
|
| 38 |
-
|
| 39 |
-
The path forward is clearer than ever. The focus should now be entirely on using the new data layer to bring the agents to life.
|
| 40 |
-
|
| 41 |
-
1. **Finalize Cleanup:** Delete the obsolete `src/cluas_mcp/common/api_clients.py` file to complete the refactoring.
|
| 42 |
-
|
| 43 |
-
2. **Integrate the Data Layer into `Corvus`:**
|
| 44 |
-
* Modify `src/characters/corvus.py`.
|
| 45 |
-
* Remove the direct imports for the old clients.
|
| 46 |
-
* Import and use the new `academic_search` facade from `src/cluas_mcp/academic/academic_search.py`.
|
| 47 |
-
* The logic inside `CorvusMCP.search_papers` should now be incredibly simple: it just needs to call `academic_search` and process the unified results.
|
| 48 |
-
|
| 49 |
-
3. **Build the `CouncilOrchestrator`:** With `Corvus` now fully functional, it is time to build the central nervous system.
|
| 50 |
-
* Create `src/orchestrator.py` as planned in the development guide.
|
| 51 |
-
* Implement a basic `process_query` method that initializes `Corvus` and calls its `search_papers` method.
|
| 52 |
-
|
| 53 |
-
4. **Connect to the UI:** Wire the new `CouncilOrchestrator` to the Gradio app. The `respond` function in `src/gradio/app.py` should do nothing more than pass the user's message to the orchestrator and display the result.
|
| 54 |
-
|
| 55 |
-
Achieving these next steps will fulfill the project's "Week 1, Day 1-2" goal and create a true end-to-end, functional application for the first time. The project has tremendous momentum; maintaining it through these next steps will bring the vision to life.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reviews/code_review_2025-11-18_19-00-00.md
DELETED
|
@@ -1,54 +0,0 @@
|
|
| 1 |
-
# Code Review: Corvid Council - Data Layer Complete
|
| 2 |
-
|
| 3 |
-
**Date:** 2025-11-18
|
| 4 |
-
|
| 5 |
-
## a) High-Level Summary
|
| 6 |
-
|
| 7 |
-
This update marks the completion of the project's data access layer. The final placeholder, the `SemanticScholarClient`, has been expertly implemented and tested, bringing the `academic` submodule to 100% functionality. The `Corvus` agent's entire toolkit for gathering academic information is now in place, is architecturally sound, and is validated by a suite of tests. This is a major milestone that concludes the foundational phase of the project and clears the way for development to move up the stack to the agent and application logic.
|
| 8 |
-
|
| 9 |
-
## b) Detailed Component Description
|
| 10 |
-
|
| 11 |
-
### `src/cluas_mcp/academic/semantic_scholar.py`
|
| 12 |
-
|
| 13 |
-
The final piece of the puzzle. This module completes the data access toolkit.
|
| 14 |
-
|
| 15 |
-
* **Functionality:** The `SemanticScholarClient` correctly queries the official API, requests a specific set of fields to keep the payload light, and normalizes the JSON response into the project's standard dictionary format. It intelligently determines if a paper is a preprint or peer-reviewed based on the presence of a DOI.
|
| 16 |
-
* **Quality:** The implementation is clean, robust (leveraging the shared `fetch_with_retry` utility), and consistent with the other clients.
|
| 17 |
-
|
| 18 |
-
### `tests/test_semantic_scholar.py`
|
| 19 |
-
|
| 20 |
-
This new test file demonstrates a continued commitment to quality.
|
| 21 |
-
|
| 22 |
-
* **Functionality:** It provides a solid integration test for the new client, asserting that the response format is correct and that key fields are present. This ensures the client is not only working now but will be protected against future regressions.
|
| 23 |
-
|
| 24 |
-
### `src/cluas_mcp/academic/academic_search_entry.py`
|
| 25 |
-
|
| 26 |
-
The facade for the `academic` module is now fully operational.
|
| 27 |
-
|
| 28 |
-
* **Functionality:** With all underlying clients implemented, this entry point can now successfully query PubMed, ArXiv, and Semantic Scholar in parallel, providing a rich, aggregated set of results from a single function call.
|
| 29 |
-
|
| 30 |
-
## c) Opinionated Breakdown & Future Development
|
| 31 |
-
|
| 32 |
-
### Current State
|
| 33 |
-
|
| 34 |
-
The project's data access layer is now a model of good software engineering practices. It is:
|
| 35 |
-
* **Modular:** Each client is in its own file.
|
| 36 |
-
* **Robust:** It uses a shared, resilient HTTP client with retries.
|
| 37 |
-
* **Tested:** Each client has a corresponding integration test.
|
| 38 |
-
* **Well-abstracted:** A single facade provides a clean entry point for the rest of the application.
|
| 39 |
-
|
| 40 |
-
This part of the project can be considered "done" for the initial MVP. It is a production-ready component. The contrast between the current state and the state of the project just a few hours ago is dramatic and speaks to a period of highly effective development.
|
| 41 |
-
|
| 42 |
-
### Suggestions for Future Development
|
| 43 |
-
|
| 44 |
-
The to-do list has become very short and focused. The project is at a clear inflection point.
|
| 45 |
-
|
| 46 |
-
1. **DELETE `src/cluas_mcp/common/api_clients.py` (Immediate):** This is the last piece of technical debt from the refactoring. Deleting this obsolete file is a zero-effort task that will officially close the chapter on the initial, messy structure.
|
| 47 |
-
|
| 48 |
-
2. **Build the Application Layer (The Only Remaining Task):** The entire focus must now shift to using the newly completed data layer. The following steps, outlined in previous reviews and the development guide, are now unlocked and should be pursued in order:
|
| 49 |
-
* **Integrate into `Corvus`:** Refactor `src/characters/corvus.py` to use the `academic_search_entry.py` facade.
|
| 50 |
-
* **Build `CouncilOrchestrator`:** Create the orchestrator to manage the agent(s).
|
| 51 |
-
* **Build `Character` Base Class:** Create a base class to standardize the agent interface.
|
| 52 |
-
* **Connect to UI:** Wire the orchestrator to the Gradio app.
|
| 53 |
-
|
| 54 |
-
The project has successfully built a powerful and reliable engine. Now it's time to build the car around it.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reviews/code_review_2025-11-18_20-00-00.md
DELETED
|
@@ -1,47 +0,0 @@
|
|
| 1 |
-
# Code Review: Corvid Council - Data Layer Hardened and Finalized
|
| 2 |
-
|
| 3 |
-
**Date:** 2025-11-18
|
| 4 |
-
|
| 5 |
-
## a) High-Level Summary
|
| 6 |
-
|
| 7 |
-
This latest update represents the final hardening and cleanup of the project's data access layer. The test suite has been refactored into a more mature, layered structure, the central search facade has been made more resilient, and the last piece of technical debt from the initial refactoring has been eliminated. The `academic` module is now a production-grade component, marking the definitive end of the foundational phase of development. The project is in an ideal state to pivot entirely to building the agent and application logic.
|
| 8 |
-
|
| 9 |
-
## b) Detailed Component Description
|
| 10 |
-
|
| 11 |
-
### Test Suite (`tests/`)
|
| 12 |
-
|
| 13 |
-
The testing infrastructure has seen a significant and professional upgrade.
|
| 14 |
-
|
| 15 |
-
* **Layered Structure:** The tests are now organized into `tests/clients/` and `tests/integration/`. This is an excellent practice that separates focused, client-level tests from higher-level tests that verify the interaction between multiple components.
|
| 16 |
-
* **Integration Test:** The new `test_academic_search_entrypoint.py` is a perfect example of a good integration test. It uses mocking to isolate the search facade and verify two key behaviors: that it correctly calls all underlying clients, and that it gracefully handles an exception from one client without crashing.
|
| 17 |
-
* **Configuration:** The addition of `tests/conftest.py` to manage the test environment's system path is a standard and robust solution for making the test suite reliable and easy to run.
|
| 18 |
-
|
| 19 |
-
### `src/cluas_mcp/academic/academic_search_entrypoint.py`
|
| 20 |
-
|
| 21 |
-
The search facade has been made more resilient.
|
| 22 |
-
|
| 23 |
-
* **Error Handling:** The function now wraps each client call in a `try...except` block. This ensures that a failure from a single source (e.g., the PubMed API is down) does not prevent the function from returning successful results from the other sources. This is a crucial feature for a system that depends on multiple external services.
|
| 24 |
-
|
| 25 |
-
### Code Cleanup
|
| 26 |
-
|
| 27 |
-
* **`api_clients.py` Deleted:** The obsolete `src/cluas_mcp/common/api_clients.py` file has been deleted. This small change has a large impact, as it removes ambiguity and finalizes the major refactoring effort, leaving the codebase clean and easy to navigate.
|
| 28 |
-
|
| 29 |
-
## c) Opinionated Breakdown & Future Development
|
| 30 |
-
|
| 31 |
-
### Current State
|
| 32 |
-
|
| 33 |
-
The project is in its best state yet. The data access layer is not just "done," it is well-crafted, resilient, and thoroughly tested. The investment in the testing infrastructure will pay dividends throughout the rest of the development cycle, allowing for faster and more confident changes. The developer has successfully navigated the transition from rapid prototyping to building stable, high-quality components.
|
| 34 |
-
|
| 35 |
-
There are no remaining issues or concerns with the foundational code. The table is perfectly set for the next course.
|
| 36 |
-
|
| 37 |
-
### Suggestions for Future Development
|
| 38 |
-
|
| 39 |
-
The focus must now shift entirely to the application layer. The next steps are clear and build directly upon the solid foundation that has been established.
|
| 40 |
-
|
| 41 |
-
1. **Integrate the Facade into `Corvus`:** This is the immediate next step. Refactor `src/characters/corvus.py` to import and use the `academic_search` function from the entrypoint. The agent's internal logic will become dramatically simpler, as it no longer needs to know about the individual clients.
|
| 42 |
-
|
| 43 |
-
2. **Build the `CouncilOrchestrator`:** With a fully functional `Corvus` agent, the orchestrator can now be built to manage it. Create `src/orchestrator.py` and implement the logic to receive a query and dispatch it to the `Corvus` agent.
|
| 44 |
-
|
| 45 |
-
3. **Connect to the UI:** Wire the orchestrator to the Gradio app in `src/gradio/app.py`. This will create the first end-to-end functional slice of the application, where a user can type a query into the UI and see real, structured data from three academic sources returned.
|
| 46 |
-
|
| 47 |
-
The project has excellent momentum and a very clear path forward. Executing on these next steps will finally bring the core vision of the application to life.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/characters/corvus.py
CHANGED
|
@@ -1,100 +0,0 @@
|
|
| 1 |
-
import time
|
| 2 |
-
from typing import List, Optional, Dict
|
| 3 |
-
from ..cluas_mcp.common.memory import AgentMemory
|
| 4 |
-
from ..cluas_mcp.academic.academic_search_entrypoint import academic_search
|
| 5 |
-
from ..cluas_mcp.common.formatting import format_authors, snippet_abstract
|
| 6 |
-
|
| 7 |
-
# init shared council memory
|
| 8 |
-
memory = AgentMemory(memory_file="src/data/memory.json")
|
| 9 |
-
|
| 10 |
-
class CorvusMCP:
|
| 11 |
-
"""
|
| 12 |
-
Corvus MCP tool: searches academic literature and returns structured results.
|
| 13 |
-
Automatically logs items into shared agent memory for council context.
|
| 14 |
-
"""
|
| 15 |
-
|
| 16 |
-
def search_papers(
|
| 17 |
-
self,
|
| 18 |
-
query: str,
|
| 19 |
-
max_results: int = 5, # Note: max_results is not currently passed to the facade
|
| 20 |
-
memory_days: int = 30
|
| 21 |
-
) -> List[Dict]:
|
| 22 |
-
"""
|
| 23 |
-
Search academic papers for a query string.
|
| 24 |
-
Returns a list of dicts:
|
| 25 |
-
{
|
| 26 |
-
"title": str,
|
| 27 |
-
"abstract": str,
|
| 28 |
-
"authors": str,
|
| 29 |
-
"published": str,
|
| 30 |
-
"doi": Optional[str],
|
| 31 |
-
"link": str
|
| 32 |
-
}
|
| 33 |
-
"""
|
| 34 |
-
|
| 35 |
-
# --- 1. Call the academic search facade ---
|
| 36 |
-
all_results = academic_search(query)
|
| 37 |
-
|
| 38 |
-
# --- 2. Combine results from all sources ---
|
| 39 |
-
results = []
|
| 40 |
-
for source in all_results.values():
|
| 41 |
-
results.extend(source)
|
| 42 |
-
|
| 43 |
-
# --- 3. Clean, format, and log results to memory ---
|
| 44 |
-
cleaned = []
|
| 45 |
-
for r in results:
|
| 46 |
-
title = r.get("title", "Untitled")
|
| 47 |
-
abstract = snippet_abstract(r.get("abstract", ""))
|
| 48 |
-
# The new clients provide 'author_str' directly
|
| 49 |
-
authors = r.get("author_str") or format_authors(r.get("authors", []))
|
| 50 |
-
doi = r.get("doi")
|
| 51 |
-
link = r.get("link", r.get("arxiv_link", r.get("pubmed_link", "")))
|
| 52 |
-
|
| 53 |
-
# log into memory
|
| 54 |
-
memory.add_item(
|
| 55 |
-
title=title,
|
| 56 |
-
doi=doi,
|
| 57 |
-
snippet=abstract,
|
| 58 |
-
mentioned_by="Corvus",
|
| 59 |
-
tags=["academic_search", r.get("source", "unknown")]
|
| 60 |
-
)
|
| 61 |
-
|
| 62 |
-
cleaned.append({
|
| 63 |
-
"title": title,
|
| 64 |
-
"abstract": abstract,
|
| 65 |
-
"authors": authors,
|
| 66 |
-
"published": r.get("published", r.get("year", "")),
|
| 67 |
-
"doi": doi,
|
| 68 |
-
"link": link
|
| 69 |
-
})
|
| 70 |
-
|
| 71 |
-
# --- 4. Include recent memory items optionally ---
|
| 72 |
-
recent_memory = memory.get_recent(days=memory_days)
|
| 73 |
-
for item in recent_memory:
|
| 74 |
-
if item["title"] not in [c["title"] for c in cleaned]:
|
| 75 |
-
cleaned.append({
|
| 76 |
-
"title": item["title"],
|
| 77 |
-
"abstract": item.get("snippet", ""),
|
| 78 |
-
"authors": "", # optional: keep minimal
|
| 79 |
-
"published": "",
|
| 80 |
-
"doi": item.get("doi"),
|
| 81 |
-
"link": item.get("doi") or "",
|
| 82 |
-
})
|
| 83 |
-
|
| 84 |
-
return cleaned
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
# poss usage example:
|
| 91 |
-
|
| 92 |
-
# from src.characters.corvus import CorvusMCP
|
| 93 |
-
|
| 94 |
-
# corvus = CorvusMCP()
|
| 95 |
-
# papers = corvus.search_papers("corvid cognition", max_results=3)
|
| 96 |
-
|
| 97 |
-
# for p in papers:
|
| 98 |
-
# print(f"{p['title']} ({p.get('doi')})")
|
| 99 |
-
# print(f"Snippet: {p['abstract']}\n")
|
| 100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/cluas_mcp/server.py
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
|
|
| 1 |
import logging
|
| 2 |
|
| 3 |
def main():
|
| 4 |
logging.basicConfig(level=logging.INFO)
|
| 5 |
-
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import FastMCP
|
| 2 |
import logging
|
| 3 |
|
| 4 |
def main():
|
| 5 |
logging.basicConfig(level=logging.INFO)
|
| 6 |
+
pass
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
@mcp.tool()
|
| 10 |
+
async def search_academic_papers(query: str) -> str:
|
| 11 |
+
"""Search academic papers across PubMed, Semantic Scholar, and ArXiv.
|
| 12 |
+
|
| 13 |
+
Args:
|
| 14 |
+
query: Search term for academic papers
|
| 15 |
+
|
| 16 |
+
Returns:
|
| 17 |
+
JSON string with results from all three sources
|
| 18 |
+
"""
|
| 19 |
+
# Call the existing academic_search function
|
| 20 |
+
# Format results as clean JSON string
|
| 21 |
+
# Include paper titles, authors, abstracts, DOIs where available
|
src/orchestrator.py
CHANGED
|
@@ -1,45 +0,0 @@
|
|
| 1 |
-
from typing import Dict, List
|
| 2 |
-
from src.characters.corvus import CorvusMCP
|
| 3 |
-
|
| 4 |
-
class CouncilOrchestrator:
|
| 5 |
-
"""
|
| 6 |
-
Manages the council of agents and orchestrates the research process.
|
| 7 |
-
"""
|
| 8 |
-
|
| 9 |
-
def __init__(self):
|
| 10 |
-
"""
|
| 11 |
-
Initializes the orchestrator and the council members.
|
| 12 |
-
For now, only Corvus is instantiated.
|
| 13 |
-
"""
|
| 14 |
-
self.corvus = CorvusMCP()
|
| 15 |
-
# In the future, other agents like Magpie, Raven, etc., will be initialized here.
|
| 16 |
-
|
| 17 |
-
def process_query(self, query: str) -> List[Dict]:
|
| 18 |
-
"""
|
| 19 |
-
Processes a user query by dispatching it to the relevant agents.
|
| 20 |
-
|
| 21 |
-
For this initial implementation, it only calls Corvus.
|
| 22 |
-
|
| 23 |
-
Args:
|
| 24 |
-
query: The user's research query.
|
| 25 |
-
|
| 26 |
-
Returns:
|
| 27 |
-
A list of dictionaries containing the search results.
|
| 28 |
-
"""
|
| 29 |
-
# In the future, this method will involve more complex logic,
|
| 30 |
-
# such as selecting which agent to call first, facilitating debate,
|
| 31 |
-
# and synthesizing results.
|
| 32 |
-
|
| 33 |
-
# For now, we just call Corvus directly.
|
| 34 |
-
results = self.corvus.search_papers(query)
|
| 35 |
-
|
| 36 |
-
return results
|
| 37 |
-
|
| 38 |
-
# Example usage (for testing):
|
| 39 |
-
# if __name__ == "__main__":
|
| 40 |
-
# orchestrator = CouncilOrchestrator()
|
| 41 |
-
# search_results = orchestrator.process_query("corvid cognition")
|
| 42 |
-
# for paper in search_results:
|
| 43 |
-
# print(f"Title: {paper['title']}")
|
| 44 |
-
# print(f"Authors: {paper['authors']}")
|
| 45 |
-
# print("-" * 20)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uv.lock
CHANGED
|
@@ -122,6 +122,15 @@ wheels = [
|
|
| 122 |
{ url = "https://files.pythonhosted.org/packages/f8/aa/5082412d1ee302e9e7d80b6949bc4d2a8fa1149aaab610c5fc24709605d6/authlib-1.6.5-py2.py3-none-any.whl", hash = "sha256:3e0e0507807f842b02175507bdee8957a1d5707fd4afb17c32fb43fee90b6e3a", size = 243608, upload-time = "2025-10-02T13:36:07.637Z" },
|
| 123 |
]
|
| 124 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
[[package]]
|
| 126 |
name = "brotli"
|
| 127 |
version = "1.2.0"
|
|
@@ -150,6 +159,15 @@ wheels = [
|
|
| 150 |
{ url = "https://files.pythonhosted.org/packages/f5/10/56978295c14794b2c12007b07f3e41ba26acda9257457d7085b0bb3bb90c/brotli-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:e7c0af964e0b4e3412a0ebf341ea26ec767fa0b4cf81abb5e897c9338b5ad6a3", size = 375639, upload-time = "2025-11-05T18:38:55.67Z" },
|
| 151 |
]
|
| 152 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
[[package]]
|
| 154 |
name = "certifi"
|
| 155 |
version = "2025.11.12"
|
|
@@ -262,6 +280,7 @@ name = "cluas"
|
|
| 262 |
version = "0.1.0"
|
| 263 |
source = { virtual = "." }
|
| 264 |
dependencies = [
|
|
|
|
| 265 |
{ name = "feedparser" },
|
| 266 |
{ name = "gradio", extra = ["mcp", "oauth"] },
|
| 267 |
{ name = "mcp" },
|
|
@@ -272,6 +291,7 @@ dependencies = [
|
|
| 272 |
|
| 273 |
[package.metadata]
|
| 274 |
requires-dist = [
|
|
|
|
| 275 |
{ name = "feedparser", specifier = ">=6.0.12" },
|
| 276 |
{ name = "gradio", extras = ["mcp", "oauth"], specifier = "==6.0.0.dev4" },
|
| 277 |
{ name = "mcp", specifier = ">=1.20.0" },
|
|
@@ -345,6 +365,69 @@ wheels = [
|
|
| 345 |
{ url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" },
|
| 346 |
]
|
| 347 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
[[package]]
|
| 349 |
name = "fastapi"
|
| 350 |
version = "0.121.2"
|
|
@@ -360,6 +443,32 @@ wheels = [
|
|
| 360 |
{ url = "https://files.pythonhosted.org/packages/eb/23/dfb161e91db7c92727db505dc72a384ee79681fe0603f706f9f9f52c2901/fastapi-0.121.2-py3-none-any.whl", hash = "sha256:f2d80b49a86a846b70cc3a03eb5ea6ad2939298bf6a7fe377aa9cd3dd079d358", size = 109201, upload-time = "2025-11-13T17:05:52.718Z" },
|
| 361 |
]
|
| 362 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 363 |
[[package]]
|
| 364 |
name = "feedparser"
|
| 365 |
version = "6.0.12"
|
|
@@ -596,6 +705,48 @@ wheels = [
|
|
| 596 |
{ url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" },
|
| 597 |
]
|
| 598 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 599 |
[[package]]
|
| 600 |
name = "jinja2"
|
| 601 |
version = "3.1.6"
|
|
@@ -623,6 +774,21 @@ wheels = [
|
|
| 623 |
{ url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" },
|
| 624 |
]
|
| 625 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 626 |
[[package]]
|
| 627 |
name = "jsonschema-specifications"
|
| 628 |
version = "2025.9.1"
|
|
@@ -635,6 +801,23 @@ wheels = [
|
|
| 635 |
{ url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" },
|
| 636 |
]
|
| 637 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 638 |
[[package]]
|
| 639 |
name = "markdown-it-py"
|
| 640 |
version = "4.0.0"
|
|
@@ -733,6 +916,15 @@ wheels = [
|
|
| 733 |
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
| 734 |
]
|
| 735 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 736 |
[[package]]
|
| 737 |
name = "numpy"
|
| 738 |
version = "2.3.5"
|
|
@@ -785,6 +977,18 @@ wheels = [
|
|
| 785 |
{ url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459, upload-time = "2025-11-16T22:52:20.55Z" },
|
| 786 |
]
|
| 787 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 788 |
[[package]]
|
| 789 |
name = "orjson"
|
| 790 |
version = "3.11.4"
|
|
@@ -872,6 +1076,27 @@ wheels = [
|
|
| 872 |
{ url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" },
|
| 873 |
]
|
| 874 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 875 |
[[package]]
|
| 876 |
name = "pillow"
|
| 877 |
version = "11.3.0"
|
|
@@ -927,6 +1152,15 @@ wheels = [
|
|
| 927 |
{ url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" },
|
| 928 |
]
|
| 929 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 930 |
[[package]]
|
| 931 |
name = "pluggy"
|
| 932 |
version = "1.6.0"
|
|
@@ -936,6 +1170,44 @@ wheels = [
|
|
| 936 |
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
| 937 |
]
|
| 938 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 939 |
[[package]]
|
| 940 |
name = "pycparser"
|
| 941 |
version = "2.23"
|
|
@@ -960,6 +1232,11 @@ wheels = [
|
|
| 960 |
{ url = "https://files.pythonhosted.org/packages/82/2f/e68750da9b04856e2a7ec56fc6f034a5a79775e9b9a81882252789873798/pydantic-2.12.4-py3-none-any.whl", hash = "sha256:92d3d202a745d46f9be6df459ac5a064fdaa3c1c4cd8adcfa332ccf3c05f871e", size = 463400, upload-time = "2025-11-05T10:50:06.732Z" },
|
| 961 |
]
|
| 962 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 963 |
[[package]]
|
| 964 |
name = "pydantic-core"
|
| 965 |
version = "2.41.5"
|
|
@@ -1059,6 +1336,24 @@ crypto = [
|
|
| 1059 |
{ name = "cryptography" },
|
| 1060 |
]
|
| 1061 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1062 |
[[package]]
|
| 1063 |
name = "pytest"
|
| 1064 |
version = "9.0.1"
|
|
@@ -1127,6 +1422,15 @@ wheels = [
|
|
| 1127 |
{ url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" },
|
| 1128 |
]
|
| 1129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1130 |
[[package]]
|
| 1131 |
name = "pyyaml"
|
| 1132 |
version = "6.0.3"
|
|
@@ -1165,15 +1469,15 @@ wheels = [
|
|
| 1165 |
|
| 1166 |
[[package]]
|
| 1167 |
name = "referencing"
|
| 1168 |
-
version = "0.
|
| 1169 |
source = { registry = "https://pypi.org/simple" }
|
| 1170 |
dependencies = [
|
| 1171 |
{ name = "attrs" },
|
| 1172 |
{ name = "rpds-py" },
|
| 1173 |
]
|
| 1174 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 1175 |
wheels = [
|
| 1176 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1177 |
]
|
| 1178 |
|
| 1179 |
[[package]]
|
|
@@ -1282,6 +1586,19 @@ wheels = [
|
|
| 1282 |
{ url = "https://files.pythonhosted.org/packages/2e/a3/0f0b7d78e2f1eb9e8e1afbff1d2bff8d60144aee17aca51c065b516743dd/safehttpx-0.1.7-py3-none-any.whl", hash = "sha256:c4f4a162db6993464d7ca3d7cc4af0ffc6515a606dfd220b9f82c6945d869cde", size = 8959, upload-time = "2025-10-24T18:30:08.733Z" },
|
| 1283 |
]
|
| 1284 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1285 |
[[package]]
|
| 1286 |
name = "semantic-version"
|
| 1287 |
version = "2.10.0"
|
|
@@ -1457,3 +1774,23 @@ sdist = { url = "https://files.pythonhosted.org/packages/cb/ce/f06b84e2697fef468
|
|
| 1457 |
wheels = [
|
| 1458 |
{ url = "https://files.pythonhosted.org/packages/ee/d9/d88e73ca598f4f6ff671fb5fde8a32925c2e08a637303a1d12883c7305fa/uvicorn-0.38.0-py3-none-any.whl", hash = "sha256:48c0afd214ceb59340075b4a052ea1ee91c16fbc2a9b1469cca0e54566977b02", size = 68109, upload-time = "2025-10-18T13:46:42.958Z" },
|
| 1459 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
{ url = "https://files.pythonhosted.org/packages/f8/aa/5082412d1ee302e9e7d80b6949bc4d2a8fa1149aaab610c5fc24709605d6/authlib-1.6.5-py2.py3-none-any.whl", hash = "sha256:3e0e0507807f842b02175507bdee8957a1d5707fd4afb17c32fb43fee90b6e3a", size = 243608, upload-time = "2025-10-02T13:36:07.637Z" },
|
| 123 |
]
|
| 124 |
|
| 125 |
+
[[package]]
|
| 126 |
+
name = "beartype"
|
| 127 |
+
version = "0.22.6"
|
| 128 |
+
source = { registry = "https://pypi.org/simple" }
|
| 129 |
+
sdist = { url = "https://files.pythonhosted.org/packages/88/e2/105ceb1704cb80fe4ab3872529ab7b6f365cf7c74f725e6132d0efcf1560/beartype-0.22.6.tar.gz", hash = "sha256:97fbda69c20b48c5780ac2ca60ce3c1bb9af29b3a1a0216898ffabdd523e48f4", size = 1588975, upload-time = "2025-11-20T04:47:14.736Z" }
|
| 130 |
+
wheels = [
|
| 131 |
+
{ url = "https://files.pythonhosted.org/packages/98/c9/ceecc71fe2c9495a1d8e08d44f5f31f5bca1350d5b2e27a4b6265424f59e/beartype-0.22.6-py3-none-any.whl", hash = "sha256:0584bc46a2ea2a871509679278cda992eadde676c01356ab0ac77421f3c9a093", size = 1324807, upload-time = "2025-11-20T04:47:11.837Z" },
|
| 132 |
+
]
|
| 133 |
+
|
| 134 |
[[package]]
|
| 135 |
name = "brotli"
|
| 136 |
version = "1.2.0"
|
|
|
|
| 159 |
{ url = "https://files.pythonhosted.org/packages/f5/10/56978295c14794b2c12007b07f3e41ba26acda9257457d7085b0bb3bb90c/brotli-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:e7c0af964e0b4e3412a0ebf341ea26ec767fa0b4cf81abb5e897c9338b5ad6a3", size = 375639, upload-time = "2025-11-05T18:38:55.67Z" },
|
| 160 |
]
|
| 161 |
|
| 162 |
+
[[package]]
|
| 163 |
+
name = "cachetools"
|
| 164 |
+
version = "6.2.2"
|
| 165 |
+
source = { registry = "https://pypi.org/simple" }
|
| 166 |
+
sdist = { url = "https://files.pythonhosted.org/packages/fb/44/ca1675be2a83aeee1886ab745b28cda92093066590233cc501890eb8417a/cachetools-6.2.2.tar.gz", hash = "sha256:8e6d266b25e539df852251cfd6f990b4bc3a141db73b939058d809ebd2590fc6", size = 31571, upload-time = "2025-11-13T17:42:51.465Z" }
|
| 167 |
+
wheels = [
|
| 168 |
+
{ url = "https://files.pythonhosted.org/packages/e6/46/eb6eca305c77a4489affe1c5d8f4cae82f285d9addd8de4ec084a7184221/cachetools-6.2.2-py3-none-any.whl", hash = "sha256:6c09c98183bf58560c97b2abfcedcbaf6a896a490f534b031b661d3723b45ace", size = 11503, upload-time = "2025-11-13T17:42:50.232Z" },
|
| 169 |
+
]
|
| 170 |
+
|
| 171 |
[[package]]
|
| 172 |
name = "certifi"
|
| 173 |
version = "2025.11.12"
|
|
|
|
| 280 |
version = "0.1.0"
|
| 281 |
source = { virtual = "." }
|
| 282 |
dependencies = [
|
| 283 |
+
{ name = "fastmcp" },
|
| 284 |
{ name = "feedparser" },
|
| 285 |
{ name = "gradio", extra = ["mcp", "oauth"] },
|
| 286 |
{ name = "mcp" },
|
|
|
|
| 291 |
|
| 292 |
[package.metadata]
|
| 293 |
requires-dist = [
|
| 294 |
+
{ name = "fastmcp", specifier = ">=2.13.1" },
|
| 295 |
{ name = "feedparser", specifier = ">=6.0.12" },
|
| 296 |
{ name = "gradio", extras = ["mcp", "oauth"], specifier = "==6.0.0.dev4" },
|
| 297 |
{ name = "mcp", specifier = ">=1.20.0" },
|
|
|
|
| 365 |
{ url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" },
|
| 366 |
]
|
| 367 |
|
| 368 |
+
[[package]]
|
| 369 |
+
name = "cyclopts"
|
| 370 |
+
version = "5.0.0a1"
|
| 371 |
+
source = { registry = "https://pypi.org/simple" }
|
| 372 |
+
dependencies = [
|
| 373 |
+
{ name = "attrs" },
|
| 374 |
+
{ name = "docstring-parser" },
|
| 375 |
+
{ name = "rich" },
|
| 376 |
+
]
|
| 377 |
+
sdist = { url = "https://files.pythonhosted.org/packages/4c/ca/65e020717410cff8916bae89d5b1704ee190d2a345f47ba5e5f903b41d59/cyclopts-5.0.0a1.tar.gz", hash = "sha256:ae24ce6c0c8dbaba3fdfccdb54d2a9d6e2a6270c47ffe101af1de89ff617851a", size = 148291, upload-time = "2025-11-02T19:32:43.176Z" }
|
| 378 |
+
wheels = [
|
| 379 |
+
{ url = "https://files.pythonhosted.org/packages/d1/d3/eda07755dffa4ea637a673181934bcd54255def1c71dd1cc0f8ec49f888e/cyclopts-5.0.0a1-py3-none-any.whl", hash = "sha256:731e0c4412d47993202abffd0bfe222353b12347dfef7e874ac769c74c8a162a", size = 183923, upload-time = "2025-11-02T19:32:41.532Z" },
|
| 380 |
+
]
|
| 381 |
+
|
| 382 |
+
[[package]]
|
| 383 |
+
name = "diskcache"
|
| 384 |
+
version = "5.6.3"
|
| 385 |
+
source = { registry = "https://pypi.org/simple" }
|
| 386 |
+
sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916, upload-time = "2023-08-31T06:12:00.316Z" }
|
| 387 |
+
wheels = [
|
| 388 |
+
{ url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550, upload-time = "2023-08-31T06:11:58.822Z" },
|
| 389 |
+
]
|
| 390 |
+
|
| 391 |
+
[[package]]
|
| 392 |
+
name = "dnspython"
|
| 393 |
+
version = "2.8.0"
|
| 394 |
+
source = { registry = "https://pypi.org/simple" }
|
| 395 |
+
sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" }
|
| 396 |
+
wheels = [
|
| 397 |
+
{ url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
|
| 398 |
+
]
|
| 399 |
+
|
| 400 |
+
[[package]]
|
| 401 |
+
name = "docstring-parser"
|
| 402 |
+
version = "0.17.0"
|
| 403 |
+
source = { registry = "https://pypi.org/simple" }
|
| 404 |
+
sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" }
|
| 405 |
+
wheels = [
|
| 406 |
+
{ url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" },
|
| 407 |
+
]
|
| 408 |
+
|
| 409 |
+
[[package]]
|
| 410 |
+
name = "email-validator"
|
| 411 |
+
version = "2.3.0"
|
| 412 |
+
source = { registry = "https://pypi.org/simple" }
|
| 413 |
+
dependencies = [
|
| 414 |
+
{ name = "dnspython" },
|
| 415 |
+
{ name = "idna" },
|
| 416 |
+
]
|
| 417 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" }
|
| 418 |
+
wheels = [
|
| 419 |
+
{ url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" },
|
| 420 |
+
]
|
| 421 |
+
|
| 422 |
+
[[package]]
|
| 423 |
+
name = "exceptiongroup"
|
| 424 |
+
version = "1.3.0"
|
| 425 |
+
source = { registry = "https://pypi.org/simple" }
|
| 426 |
+
sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" }
|
| 427 |
+
wheels = [
|
| 428 |
+
{ url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" },
|
| 429 |
+
]
|
| 430 |
+
|
| 431 |
[[package]]
|
| 432 |
name = "fastapi"
|
| 433 |
version = "0.121.2"
|
|
|
|
| 443 |
{ url = "https://files.pythonhosted.org/packages/eb/23/dfb161e91db7c92727db505dc72a384ee79681fe0603f706f9f9f52c2901/fastapi-0.121.2-py3-none-any.whl", hash = "sha256:f2d80b49a86a846b70cc3a03eb5ea6ad2939298bf6a7fe377aa9cd3dd079d358", size = 109201, upload-time = "2025-11-13T17:05:52.718Z" },
|
| 444 |
]
|
| 445 |
|
| 446 |
+
[[package]]
|
| 447 |
+
name = "fastmcp"
|
| 448 |
+
version = "2.13.1"
|
| 449 |
+
source = { registry = "https://pypi.org/simple" }
|
| 450 |
+
dependencies = [
|
| 451 |
+
{ name = "authlib" },
|
| 452 |
+
{ name = "cyclopts" },
|
| 453 |
+
{ name = "exceptiongroup" },
|
| 454 |
+
{ name = "httpx" },
|
| 455 |
+
{ name = "jsonschema-path" },
|
| 456 |
+
{ name = "mcp" },
|
| 457 |
+
{ name = "openapi-pydantic" },
|
| 458 |
+
{ name = "platformdirs" },
|
| 459 |
+
{ name = "py-key-value-aio", extra = ["disk", "keyring", "memory"] },
|
| 460 |
+
{ name = "pydantic", extra = ["email"] },
|
| 461 |
+
{ name = "pyperclip" },
|
| 462 |
+
{ name = "python-dotenv" },
|
| 463 |
+
{ name = "rich" },
|
| 464 |
+
{ name = "uvicorn" },
|
| 465 |
+
{ name = "websockets" },
|
| 466 |
+
]
|
| 467 |
+
sdist = { url = "https://files.pythonhosted.org/packages/d4/a3/c9eb28b5f0b979b0dd8aa9ba56e69298cdb2d72c15592165d042ccb20194/fastmcp-2.13.1.tar.gz", hash = "sha256:b9c664c51f1ff47c698225e7304267ae29a51913f681bd49e442b8682f9a5f90", size = 8170226, upload-time = "2025-11-15T19:02:17.693Z" }
|
| 468 |
+
wheels = [
|
| 469 |
+
{ url = "https://files.pythonhosted.org/packages/9b/4b/7e36db0a90044be181319ff025be7cc57089ddb6ba8f3712dea543b9cf97/fastmcp-2.13.1-py3-none-any.whl", hash = "sha256:7a78b19785c4ec04a758d920c312769a497e3f6ab4c80feed504df1ed7de9f3c", size = 376750, upload-time = "2025-11-15T19:02:15.748Z" },
|
| 470 |
+
]
|
| 471 |
+
|
| 472 |
[[package]]
|
| 473 |
name = "feedparser"
|
| 474 |
version = "6.0.12"
|
|
|
|
| 705 |
{ url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" },
|
| 706 |
]
|
| 707 |
|
| 708 |
+
[[package]]
|
| 709 |
+
name = "jaraco-classes"
|
| 710 |
+
version = "3.4.0"
|
| 711 |
+
source = { registry = "https://pypi.org/simple" }
|
| 712 |
+
dependencies = [
|
| 713 |
+
{ name = "more-itertools" },
|
| 714 |
+
]
|
| 715 |
+
sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" }
|
| 716 |
+
wheels = [
|
| 717 |
+
{ url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777, upload-time = "2024-03-31T07:27:34.792Z" },
|
| 718 |
+
]
|
| 719 |
+
|
| 720 |
+
[[package]]
|
| 721 |
+
name = "jaraco-context"
|
| 722 |
+
version = "6.0.1"
|
| 723 |
+
source = { registry = "https://pypi.org/simple" }
|
| 724 |
+
sdist = { url = "https://files.pythonhosted.org/packages/df/ad/f3777b81bf0b6e7bc7514a1656d3e637b2e8e15fab2ce3235730b3e7a4e6/jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", size = 13912, upload-time = "2024-08-20T03:39:27.358Z" }
|
| 725 |
+
wheels = [
|
| 726 |
+
{ url = "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4", size = 6825, upload-time = "2024-08-20T03:39:25.966Z" },
|
| 727 |
+
]
|
| 728 |
+
|
| 729 |
+
[[package]]
|
| 730 |
+
name = "jaraco-functools"
|
| 731 |
+
version = "4.3.0"
|
| 732 |
+
source = { registry = "https://pypi.org/simple" }
|
| 733 |
+
dependencies = [
|
| 734 |
+
{ name = "more-itertools" },
|
| 735 |
+
]
|
| 736 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f7/ed/1aa2d585304ec07262e1a83a9889880701079dde796ac7b1d1826f40c63d/jaraco_functools-4.3.0.tar.gz", hash = "sha256:cfd13ad0dd2c47a3600b439ef72d8615d482cedcff1632930d6f28924d92f294", size = 19755, upload-time = "2025-08-18T20:05:09.91Z" }
|
| 737 |
+
wheels = [
|
| 738 |
+
{ url = "https://files.pythonhosted.org/packages/b4/09/726f168acad366b11e420df31bf1c702a54d373a83f968d94141a8c3fde0/jaraco_functools-4.3.0-py3-none-any.whl", hash = "sha256:227ff8ed6f7b8f62c56deff101545fa7543cf2c8e7b82a7c2116e672f29c26e8", size = 10408, upload-time = "2025-08-18T20:05:08.69Z" },
|
| 739 |
+
]
|
| 740 |
+
|
| 741 |
+
[[package]]
|
| 742 |
+
name = "jeepney"
|
| 743 |
+
version = "0.9.0"
|
| 744 |
+
source = { registry = "https://pypi.org/simple" }
|
| 745 |
+
sdist = { url = "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", size = 106758, upload-time = "2025-02-27T18:51:01.684Z" }
|
| 746 |
+
wheels = [
|
| 747 |
+
{ url = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", size = 49010, upload-time = "2025-02-27T18:51:00.104Z" },
|
| 748 |
+
]
|
| 749 |
+
|
| 750 |
[[package]]
|
| 751 |
name = "jinja2"
|
| 752 |
version = "3.1.6"
|
|
|
|
| 774 |
{ url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" },
|
| 775 |
]
|
| 776 |
|
| 777 |
+
[[package]]
|
| 778 |
+
name = "jsonschema-path"
|
| 779 |
+
version = "0.4.0b1"
|
| 780 |
+
source = { registry = "https://pypi.org/simple" }
|
| 781 |
+
dependencies = [
|
| 782 |
+
{ name = "pathable" },
|
| 783 |
+
{ name = "pyrsistent" },
|
| 784 |
+
{ name = "pyyaml" },
|
| 785 |
+
{ name = "referencing" },
|
| 786 |
+
]
|
| 787 |
+
sdist = { url = "https://files.pythonhosted.org/packages/0f/b9/eb99f1367ebcf8d6e2ae4f1c6e3da61eeb0ddd11c2695b1cdad8a9dad631/jsonschema_path-0.4.0b1.tar.gz", hash = "sha256:4678dcb27e5fbc58b39baf7ca8c36a6a7de3bcafacaaafc1b8a1d54038ce8d8a", size = 11807, upload-time = "2025-06-07T20:52:58.9Z" }
|
| 788 |
+
wheels = [
|
| 789 |
+
{ url = "https://files.pythonhosted.org/packages/67/f5/24d5b91ed0409989140d1d4217e9c852d81782ced54e46b0582ad5f56dcb/jsonschema_path-0.4.0b1-py3-none-any.whl", hash = "sha256:f0cd42238c1445cecac3b2796fa24dcc62b8426623d1cb4d8d755f3715abf3ba", size = 15293, upload-time = "2025-06-07T20:52:57.029Z" },
|
| 790 |
+
]
|
| 791 |
+
|
| 792 |
[[package]]
|
| 793 |
name = "jsonschema-specifications"
|
| 794 |
version = "2025.9.1"
|
|
|
|
| 801 |
{ url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" },
|
| 802 |
]
|
| 803 |
|
| 804 |
+
[[package]]
|
| 805 |
+
name = "keyring"
|
| 806 |
+
version = "25.7.0"
|
| 807 |
+
source = { registry = "https://pypi.org/simple" }
|
| 808 |
+
dependencies = [
|
| 809 |
+
{ name = "jaraco-classes" },
|
| 810 |
+
{ name = "jaraco-context" },
|
| 811 |
+
{ name = "jaraco-functools" },
|
| 812 |
+
{ name = "jeepney", marker = "sys_platform == 'linux'" },
|
| 813 |
+
{ name = "pywin32-ctypes", marker = "sys_platform == 'win32'" },
|
| 814 |
+
{ name = "secretstorage", marker = "sys_platform == 'linux'" },
|
| 815 |
+
]
|
| 816 |
+
sdist = { url = "https://files.pythonhosted.org/packages/43/4b/674af6ef2f97d56f0ab5153bf0bfa28ccb6c3ed4d1babf4305449668807b/keyring-25.7.0.tar.gz", hash = "sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b", size = 63516, upload-time = "2025-11-16T16:26:09.482Z" }
|
| 817 |
+
wheels = [
|
| 818 |
+
{ url = "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f", size = 39160, upload-time = "2025-11-16T16:26:08.402Z" },
|
| 819 |
+
]
|
| 820 |
+
|
| 821 |
[[package]]
|
| 822 |
name = "markdown-it-py"
|
| 823 |
version = "4.0.0"
|
|
|
|
| 916 |
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
| 917 |
]
|
| 918 |
|
| 919 |
+
[[package]]
|
| 920 |
+
name = "more-itertools"
|
| 921 |
+
version = "10.8.0"
|
| 922 |
+
source = { registry = "https://pypi.org/simple" }
|
| 923 |
+
sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" }
|
| 924 |
+
wheels = [
|
| 925 |
+
{ url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" },
|
| 926 |
+
]
|
| 927 |
+
|
| 928 |
[[package]]
|
| 929 |
name = "numpy"
|
| 930 |
version = "2.3.5"
|
|
|
|
| 977 |
{ url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459, upload-time = "2025-11-16T22:52:20.55Z" },
|
| 978 |
]
|
| 979 |
|
| 980 |
+
[[package]]
|
| 981 |
+
name = "openapi-pydantic"
|
| 982 |
+
version = "0.5.1"
|
| 983 |
+
source = { registry = "https://pypi.org/simple" }
|
| 984 |
+
dependencies = [
|
| 985 |
+
{ name = "pydantic" },
|
| 986 |
+
]
|
| 987 |
+
sdist = { url = "https://files.pythonhosted.org/packages/02/2e/58d83848dd1a79cb92ed8e63f6ba901ca282c5f09d04af9423ec26c56fd7/openapi_pydantic-0.5.1.tar.gz", hash = "sha256:ff6835af6bde7a459fb93eb93bb92b8749b754fc6e51b2f1590a19dc3005ee0d", size = 60892, upload-time = "2025-01-08T19:29:27.083Z" }
|
| 988 |
+
wheels = [
|
| 989 |
+
{ url = "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl", hash = "sha256:a3a09ef4586f5bd760a8df7f43028b60cafb6d9f61de2acba9574766255ab146", size = 96381, upload-time = "2025-01-08T19:29:25.275Z" },
|
| 990 |
+
]
|
| 991 |
+
|
| 992 |
[[package]]
|
| 993 |
name = "orjson"
|
| 994 |
version = "3.11.4"
|
|
|
|
| 1076 |
{ url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" },
|
| 1077 |
]
|
| 1078 |
|
| 1079 |
+
[[package]]
|
| 1080 |
+
name = "pathable"
|
| 1081 |
+
version = "0.5.0b2"
|
| 1082 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1083 |
+
dependencies = [
|
| 1084 |
+
{ name = "pyrsistent" },
|
| 1085 |
+
]
|
| 1086 |
+
sdist = { url = "https://files.pythonhosted.org/packages/10/a0/5ce545bf5d14d3b8925e73f12f67adee7a139a6726c0df75aca25ab6e8b7/pathable-0.5.0b2.tar.gz", hash = "sha256:0005483148dc1991ab32e4cb4cde7e2b8f376f081a1639631e424db0792860e9", size = 9896, upload-time = "2025-06-07T20:45:35.764Z" }
|
| 1087 |
+
wheels = [
|
| 1088 |
+
{ url = "https://files.pythonhosted.org/packages/70/9a/8a74be1ab54bb62bd3c1554af8ef431c530f843d713785874207a77229e6/pathable-0.5.0b2-py3-none-any.whl", hash = "sha256:4c78bc5dae0c64a6191b955b7975bab58f0e298e197f591d4f0172886824a52b", size = 11374, upload-time = "2025-06-07T20:45:34.114Z" },
|
| 1089 |
+
]
|
| 1090 |
+
|
| 1091 |
+
[[package]]
|
| 1092 |
+
name = "pathvalidate"
|
| 1093 |
+
version = "3.3.1"
|
| 1094 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1095 |
+
sdist = { url = "https://files.pythonhosted.org/packages/fa/2a/52a8da6fe965dea6192eb716b357558e103aea0a1e9a8352ad575a8406ca/pathvalidate-3.3.1.tar.gz", hash = "sha256:b18c07212bfead624345bb8e1d6141cdcf15a39736994ea0b94035ad2b1ba177", size = 63262, upload-time = "2025-06-15T09:07:20.736Z" }
|
| 1096 |
+
wheels = [
|
| 1097 |
+
{ url = "https://files.pythonhosted.org/packages/9a/70/875f4a23bfc4731703a5835487d0d2fb999031bd415e7d17c0ae615c18b7/pathvalidate-3.3.1-py3-none-any.whl", hash = "sha256:5263baab691f8e1af96092fa5137ee17df5bdfbd6cff1fcac4d6ef4bc2e1735f", size = 24305, upload-time = "2025-06-15T09:07:19.117Z" },
|
| 1098 |
+
]
|
| 1099 |
+
|
| 1100 |
[[package]]
|
| 1101 |
name = "pillow"
|
| 1102 |
version = "11.3.0"
|
|
|
|
| 1152 |
{ url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" },
|
| 1153 |
]
|
| 1154 |
|
| 1155 |
+
[[package]]
|
| 1156 |
+
name = "platformdirs"
|
| 1157 |
+
version = "4.5.0"
|
| 1158 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1159 |
+
sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" }
|
| 1160 |
+
wheels = [
|
| 1161 |
+
{ url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" },
|
| 1162 |
+
]
|
| 1163 |
+
|
| 1164 |
[[package]]
|
| 1165 |
name = "pluggy"
|
| 1166 |
version = "1.6.0"
|
|
|
|
| 1170 |
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
| 1171 |
]
|
| 1172 |
|
| 1173 |
+
[[package]]
|
| 1174 |
+
name = "py-key-value-aio"
|
| 1175 |
+
version = "0.2.8"
|
| 1176 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1177 |
+
dependencies = [
|
| 1178 |
+
{ name = "beartype" },
|
| 1179 |
+
{ name = "py-key-value-shared" },
|
| 1180 |
+
]
|
| 1181 |
+
sdist = { url = "https://files.pythonhosted.org/packages/ca/35/65310a4818acec0f87a46e5565e341c5a96fc062a9a03495ad28828ff4d7/py_key_value_aio-0.2.8.tar.gz", hash = "sha256:c0cfbb0bd4e962a3fa1a9fa6db9ba9df812899bd9312fa6368aaea7b26008b36", size = 32853, upload-time = "2025-10-24T13:31:04.688Z" }
|
| 1182 |
+
wheels = [
|
| 1183 |
+
{ url = "https://files.pythonhosted.org/packages/cd/5a/e56747d87a97ad2aff0f3700d77f186f0704c90c2da03bfed9e113dae284/py_key_value_aio-0.2.8-py3-none-any.whl", hash = "sha256:561565547ce8162128fd2bd0b9d70ce04a5f4586da8500cce79a54dfac78c46a", size = 69200, upload-time = "2025-10-24T13:31:03.81Z" },
|
| 1184 |
+
]
|
| 1185 |
+
|
| 1186 |
+
[package.optional-dependencies]
|
| 1187 |
+
disk = [
|
| 1188 |
+
{ name = "diskcache" },
|
| 1189 |
+
{ name = "pathvalidate" },
|
| 1190 |
+
]
|
| 1191 |
+
keyring = [
|
| 1192 |
+
{ name = "keyring" },
|
| 1193 |
+
]
|
| 1194 |
+
memory = [
|
| 1195 |
+
{ name = "cachetools" },
|
| 1196 |
+
]
|
| 1197 |
+
|
| 1198 |
+
[[package]]
|
| 1199 |
+
name = "py-key-value-shared"
|
| 1200 |
+
version = "0.2.8"
|
| 1201 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1202 |
+
dependencies = [
|
| 1203 |
+
{ name = "beartype" },
|
| 1204 |
+
{ name = "typing-extensions" },
|
| 1205 |
+
]
|
| 1206 |
+
sdist = { url = "https://files.pythonhosted.org/packages/26/79/05a1f9280cfa0709479319cbfd2b1c5beb23d5034624f548c83fb65b0b61/py_key_value_shared-0.2.8.tar.gz", hash = "sha256:703b4d3c61af124f0d528ba85995c3c8d78f8bd3d2b217377bd3278598070cc1", size = 8216, upload-time = "2025-10-24T13:31:03.601Z" }
|
| 1207 |
+
wheels = [
|
| 1208 |
+
{ url = "https://files.pythonhosted.org/packages/84/7a/1726ceaa3343874f322dd83c9ec376ad81f533df8422b8b1e1233a59f8ce/py_key_value_shared-0.2.8-py3-none-any.whl", hash = "sha256:aff1bbfd46d065b2d67897d298642e80e5349eae588c6d11b48452b46b8d46ba", size = 14586, upload-time = "2025-10-24T13:31:02.838Z" },
|
| 1209 |
+
]
|
| 1210 |
+
|
| 1211 |
[[package]]
|
| 1212 |
name = "pycparser"
|
| 1213 |
version = "2.23"
|
|
|
|
| 1232 |
{ url = "https://files.pythonhosted.org/packages/82/2f/e68750da9b04856e2a7ec56fc6f034a5a79775e9b9a81882252789873798/pydantic-2.12.4-py3-none-any.whl", hash = "sha256:92d3d202a745d46f9be6df459ac5a064fdaa3c1c4cd8adcfa332ccf3c05f871e", size = 463400, upload-time = "2025-11-05T10:50:06.732Z" },
|
| 1233 |
]
|
| 1234 |
|
| 1235 |
+
[package.optional-dependencies]
|
| 1236 |
+
email = [
|
| 1237 |
+
{ name = "email-validator" },
|
| 1238 |
+
]
|
| 1239 |
+
|
| 1240 |
[[package]]
|
| 1241 |
name = "pydantic-core"
|
| 1242 |
version = "2.41.5"
|
|
|
|
| 1336 |
{ name = "cryptography" },
|
| 1337 |
]
|
| 1338 |
|
| 1339 |
+
[[package]]
|
| 1340 |
+
name = "pyperclip"
|
| 1341 |
+
version = "1.11.0"
|
| 1342 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1343 |
+
sdist = { url = "https://files.pythonhosted.org/packages/e8/52/d87eba7cb129b81563019d1679026e7a112ef76855d6159d24754dbd2a51/pyperclip-1.11.0.tar.gz", hash = "sha256:244035963e4428530d9e3a6101a1ef97209c6825edab1567beac148ccc1db1b6", size = 12185, upload-time = "2025-09-26T14:40:37.245Z" }
|
| 1344 |
+
wheels = [
|
| 1345 |
+
{ url = "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl", hash = "sha256:299403e9ff44581cb9ba2ffeed69c7aa96a008622ad0c46cb575ca75b5b84273", size = 11063, upload-time = "2025-09-26T14:40:36.069Z" },
|
| 1346 |
+
]
|
| 1347 |
+
|
| 1348 |
+
[[package]]
|
| 1349 |
+
name = "pyrsistent"
|
| 1350 |
+
version = "0.20.0"
|
| 1351 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1352 |
+
sdist = { url = "https://files.pythonhosted.org/packages/ce/3a/5031723c09068e9c8c2f0bc25c3a9245f2b1d1aea8396c787a408f2b95ca/pyrsistent-0.20.0.tar.gz", hash = "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4", size = 103642, upload-time = "2023-10-25T21:06:56.342Z" }
|
| 1353 |
+
wheels = [
|
| 1354 |
+
{ url = "https://files.pythonhosted.org/packages/23/88/0acd180010aaed4987c85700b7cc17f9505f3edb4e5873e4dc67f613e338/pyrsistent-0.20.0-py3-none-any.whl", hash = "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b", size = 58106, upload-time = "2023-10-25T21:06:54.387Z" },
|
| 1355 |
+
]
|
| 1356 |
+
|
| 1357 |
[[package]]
|
| 1358 |
name = "pytest"
|
| 1359 |
version = "9.0.1"
|
|
|
|
| 1422 |
{ url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" },
|
| 1423 |
]
|
| 1424 |
|
| 1425 |
+
[[package]]
|
| 1426 |
+
name = "pywin32-ctypes"
|
| 1427 |
+
version = "0.2.3"
|
| 1428 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1429 |
+
sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" }
|
| 1430 |
+
wheels = [
|
| 1431 |
+
{ url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" },
|
| 1432 |
+
]
|
| 1433 |
+
|
| 1434 |
[[package]]
|
| 1435 |
name = "pyyaml"
|
| 1436 |
version = "6.0.3"
|
|
|
|
| 1469 |
|
| 1470 |
[[package]]
|
| 1471 |
name = "referencing"
|
| 1472 |
+
version = "0.36.2"
|
| 1473 |
source = { registry = "https://pypi.org/simple" }
|
| 1474 |
dependencies = [
|
| 1475 |
{ name = "attrs" },
|
| 1476 |
{ name = "rpds-py" },
|
| 1477 |
]
|
| 1478 |
+
sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" }
|
| 1479 |
wheels = [
|
| 1480 |
+
{ url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" },
|
| 1481 |
]
|
| 1482 |
|
| 1483 |
[[package]]
|
|
|
|
| 1586 |
{ url = "https://files.pythonhosted.org/packages/2e/a3/0f0b7d78e2f1eb9e8e1afbff1d2bff8d60144aee17aca51c065b516743dd/safehttpx-0.1.7-py3-none-any.whl", hash = "sha256:c4f4a162db6993464d7ca3d7cc4af0ffc6515a606dfd220b9f82c6945d869cde", size = 8959, upload-time = "2025-10-24T18:30:08.733Z" },
|
| 1587 |
]
|
| 1588 |
|
| 1589 |
+
[[package]]
|
| 1590 |
+
name = "secretstorage"
|
| 1591 |
+
version = "3.4.1"
|
| 1592 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1593 |
+
dependencies = [
|
| 1594 |
+
{ name = "cryptography" },
|
| 1595 |
+
{ name = "jeepney" },
|
| 1596 |
+
]
|
| 1597 |
+
sdist = { url = "https://files.pythonhosted.org/packages/32/8a/ed6747b1cc723c81f526d4c12c1b1d43d07190e1e8258dbf934392fc850e/secretstorage-3.4.1.tar.gz", hash = "sha256:a799acf5be9fb93db609ebaa4ab6e8f1f3ed5ae640e0fa732bfea59e9c3b50e8", size = 19871, upload-time = "2025-11-11T11:30:23.798Z" }
|
| 1598 |
+
wheels = [
|
| 1599 |
+
{ url = "https://files.pythonhosted.org/packages/b0/6d/24ebb101484f1911a6be6695b76ce43219caa110ebbe07d8c3a5f3106cca/secretstorage-3.4.1-py3-none-any.whl", hash = "sha256:c55d57b4da3de568d8c3af89dad244ab24c35ca1da8625fc1b550edf005ebc41", size = 15301, upload-time = "2025-11-11T11:30:22.618Z" },
|
| 1600 |
+
]
|
| 1601 |
+
|
| 1602 |
[[package]]
|
| 1603 |
name = "semantic-version"
|
| 1604 |
version = "2.10.0"
|
|
|
|
| 1774 |
wheels = [
|
| 1775 |
{ url = "https://files.pythonhosted.org/packages/ee/d9/d88e73ca598f4f6ff671fb5fde8a32925c2e08a637303a1d12883c7305fa/uvicorn-0.38.0-py3-none-any.whl", hash = "sha256:48c0afd214ceb59340075b4a052ea1ee91c16fbc2a9b1469cca0e54566977b02", size = 68109, upload-time = "2025-10-18T13:46:42.958Z" },
|
| 1776 |
]
|
| 1777 |
+
|
| 1778 |
+
[[package]]
|
| 1779 |
+
name = "websockets"
|
| 1780 |
+
version = "15.0.1"
|
| 1781 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1782 |
+
sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" }
|
| 1783 |
+
wheels = [
|
| 1784 |
+
{ url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" },
|
| 1785 |
+
{ url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" },
|
| 1786 |
+
{ url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" },
|
| 1787 |
+
{ url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" },
|
| 1788 |
+
{ url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" },
|
| 1789 |
+
{ url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" },
|
| 1790 |
+
{ url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" },
|
| 1791 |
+
{ url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" },
|
| 1792 |
+
{ url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" },
|
| 1793 |
+
{ url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" },
|
| 1794 |
+
{ url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" },
|
| 1795 |
+
{ url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" },
|
| 1796 |
+
]
|