# Issue #158: Implement issue parser agent ## Objective Create an AI agent using Anthropic's Sonnet model that parses Gitea issue markdown bodies to extract structured metadata for autonomous task coordination. ## Approach ### 1. Dependencies - Add `anthropic` package to pyproject.toml - Add `ANTHROPIC_API_KEY` to config.py ### 2. Data Models (src/models.py) - `IssueMetadata`: Pydantic model for parsed metadata - `estimated_context`: int (tokens) - `difficulty`: str (easy/medium/hard) - `assigned_agent`: str (sonnet/haiku/opus/glm) - `blocks`: list[int] (issue numbers this blocks) - `blocked_by`: list[int] (issue numbers blocking this) ### 3. Parser Agent (src/parser.py) - `parse_issue_metadata(issue_body: str, issue_number: int) -> IssueMetadata` - Uses Anthropic API with claude-sonnet-4.5 model - Structured JSON extraction via prompt - Cache results using simple in-memory dict (issue_number -> metadata) - Graceful fallback to defaults on parse failure ### 4. Integration - Update `webhook.py` to call parser in `handle_assigned_event()` - Log parsed metadata ## Progress - [x] Create scratchpad - [x] Update pyproject.toml with anthropic dependency - [x] Create models.py with IssueMetadata (TEST FIRST) - [x] Create parser.py with parse function (TEST FIRST) - [x] Update config.py with ANTHROPIC_API_KEY - [x] Write comprehensive tests (9 test cases) - [x] Run quality gates (mypy, ruff, pytest) - [x] Verify 95% coverage (exceeds 85% requirement) - [x] Create .env.example - [x] Update README.md - [x] All quality gates pass - [x] Commit changes ## Testing ### Unit Tests (test_parser.py) - Test parsing complete issue body → valid metadata - Test parsing minimal issue body → defaults used - Test parsing malformed markdown → graceful failure - Test caching (same issue parsed twice = 1 API call) - Test different difficulty levels - Test blocks/blocked_by extraction - Mock Anthropic API for unit tests - Integration test with real API (optional, can be skipped if no key) ### Test Cases 1. **Complete issue body** - All fields present 2. **Minimal issue body** - Only required fields 3. **Missing Context Estimate** - Default to reasonable value 4. **Missing Difficulty** - Default to "medium" 5. **Missing Agent** - Default to "sonnet" 6. **Malformed blocks/blocked_by** - Empty lists 7. **API failure** - Return defaults with error logged 8. **Cache hit** - Second parse returns cached result ## Notes ### Default Values - estimated_context: 50000 (reasonable default for medium issues) - difficulty: "medium" - assigned_agent: "sonnet" - blocks: [] - blocked_by: [] ### Prompt Strategy Use structured output with clear instructions to extract from markdown sections: - "Context Estimate" section → estimated_context - "Difficulty" section → difficulty - "Dependencies" section → blocks, blocked_by ### Performance Target - Average parse time < 2 seconds - Cache to avoid redundant API calls - Log token usage for cost tracking ### API Integration - Use `anthropic.Anthropic()` client - Model: `claude-sonnet-4.5-20250929` - Max tokens: 1024 (responses are small) - Temperature: 0 (deterministic parsing) ## Token Tracking - Estimated: 46,800 tokens - Actual: TBD after implementation