bugsink mcp and claude subagents - documentation and test fixes
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 19m11s

This commit is contained in:
2026-01-22 11:22:56 -08:00
parent fac98f4c54
commit eae0dbaa8e
15 changed files with 747 additions and 540 deletions

View File

@@ -44,12 +44,12 @@ The ai-usage subagent understands:
## Key Files
| File | Purpose |
|------|---------|
| `src/services/aiService.server.ts` | Gemini API integration |
| `src/services/flyerProcessingService.server.ts` | Flyer extraction pipeline |
| `src/schemas/flyer.schemas.ts` | Zod schemas for AI output validation |
| `src/types/ai.types.ts` | TypeScript types for AI responses |
| File | Purpose |
| ----------------------------------------------- | ------------------------------------ |
| `src/services/aiService.server.ts` | Gemini API integration |
| `src/services/flyerProcessingService.server.ts` | Flyer extraction pipeline |
| `src/schemas/flyer.schemas.ts` | Zod schemas for AI output validation |
| `src/types/ai.types.ts` | TypeScript types for AI responses |
## Example Requests
@@ -95,6 +95,7 @@ const processedImages = await imageProcessor.prepareForAI(uploadedFile);
### 2. Prompt Construction
The extraction prompt includes:
- System instructions for the AI model
- Expected output schema (JSON)
- Examples of correct extraction
@@ -103,11 +104,7 @@ The extraction prompt includes:
### 3. API Call
```typescript
const response = await aiService.extractFlyerData(
processedImages,
storeContext,
extractionOptions
);
const response = await aiService.extractFlyerData(processedImages, storeContext, extractionOptions);
```
### 4. Response Validation
@@ -131,6 +128,7 @@ const normalizedItems = normalizeExtractedItems(validatedItems);
**Symptoms**: Same item priced differently on different extractions.
**Solution**: Improve prompt with explicit price format examples:
```
"Price formats to recognize:
- $X.XX (regular price)
@@ -145,6 +143,7 @@ const normalizedItems = normalizeExtractedItems(validatedItems);
**Symptoms**: Flyers with many items on one page have missing extractions.
**Solution**:
1. Split page into quadrants for separate extraction
2. Increase token limit for response
3. Use structured grid-based prompting
@@ -154,18 +153,23 @@ const normalizedItems = normalizeExtractedItems(validatedItems);
**Symptoms**: `429 Too Many Requests` errors during bulk uploads.
**Solution**: Implement request queuing:
```typescript
// Add to job queue instead of direct call
await flyerQueue.add('extract', {
flyerId,
images,
}, {
attempts: 3,
backoff: {
type: 'exponential',
delay: 2000,
await flyerQueue.add(
'extract',
{
flyerId,
images,
},
});
{
attempts: 3,
backoff: {
type: 'exponential',
delay: 2000,
},
},
);
```
### Issue: Hallucinated Items
@@ -173,6 +177,7 @@ await flyerQueue.add('extract', {
**Symptoms**: Items extracted that don't exist in the flyer.
**Solution**:
1. Add confidence scoring to extraction
2. Request bounding box coordinates for verification
3. Add post-extraction validation against image
@@ -227,31 +232,34 @@ For each item:
### Metrics to Track
| Metric | Description | Target |
|--------|-------------|--------|
| Extraction success rate | % of flyers processed without error | >95% |
| Items per flyer | Average items extracted | Varies by store |
| Price accuracy | Match rate vs manual verification | >98% |
| Response time | Time from upload to extraction complete | <30s |
| Metric | Description | Target |
| ----------------------- | --------------------------------------- | --------------- |
| Extraction success rate | % of flyers processed without error | >95% |
| Items per flyer | Average items extracted | Varies by store |
| Price accuracy | Match rate vs manual verification | >98% |
| Response time | Time from upload to extraction complete | <30s |
### Logging
```typescript
log.info({
flyerId,
itemCount: extractedItems.length,
processingTime: duration,
modelVersion: response.model,
tokenUsage: response.usage,
}, 'Flyer extraction completed');
log.info(
{
flyerId,
itemCount: extractedItems.length,
processingTime: duration,
modelVersion: response.model,
tokenUsage: response.usage,
},
'Flyer extraction completed',
);
```
## Environment Configuration
| Variable | Purpose |
|----------|---------|
| `VITE_GOOGLE_GENAI_API_KEY` | Gemini API key (production) |
| `VITE_GOOGLE_GENAI_API_KEY_TEST` | Gemini API key (test) |
| Variable | Purpose |
| -------------------------------- | --------------------------- |
| `VITE_GOOGLE_GENAI_API_KEY` | Gemini API key (production) |
| `VITE_GOOGLE_GENAI_API_KEY_TEST` | Gemini API key (test) |
**Note**: Use separate API keys for production and test to avoid rate limit conflicts and enable separate billing tracking.
@@ -260,6 +268,7 @@ log.info({
### Unit Tests
Mock the Gemini API response:
```typescript
vi.mock('@google/generative-ai', () => ({
GoogleGenerativeAI: vi.fn().mockImplementation(() => ({
@@ -277,6 +286,7 @@ vi.mock('@google/generative-ai', () => ({
### Integration Tests
Use recorded responses for deterministic testing:
```typescript
// Save real API responses to fixtures
const fixtureResponse = await fs.readFile('fixtures/gemini-response.json');