UNPKG

@oliverpople/agency-x

Version:

🚀 **Transform feature requests into production-ready code in seconds**

94 lines (80 loc) • 3.15 kB
import { createLogger } from '../utils/logger'; import { getContext, updateContext } from '../utils/contextStore'; import { getLlmClient } from '../llm/llmRouter'; import { productManagerPrompt, jsonRepairPrompt } from '../utils/promptTemplates'; const logger = createLogger('productManager'); const extractJsonFromResponse = (response: string): any | null => { // First try to parse the response directly try { return JSON.parse(response.trim()); } catch { // If that fails, try to extract JSON from between thinking tags or from the end const lines = response.split('\n'); let jsonStart = -1; // Look for the start of JSON (after thinking tags or just a { ) for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line === '{' || line.startsWith('{"')) { jsonStart = i; break; } // Also check if this line contains </thinking> - JSON should be after this if (line.includes('</thinking>')) { jsonStart = i + 1; break; } } if (jsonStart >= 0) { const jsonLines = lines.slice(jsonStart); const potentialJson = jsonLines.join('\n').trim(); try { return JSON.parse(potentialJson); } catch { // Try to find just the JSON object by looking for balanced braces const match = potentialJson.match(/\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}/g); if (match && match[0]) { try { return JSON.parse(match[0]); } catch { return null; } } } } return null; } }; export const runProductManager = async () => { logger.start(); const context = getContext(); const { featurePrompt } = context; const llmClient = getLlmClient(); const prompt = productManagerPrompt.replace('{{featurePrompt}}', featurePrompt); let response = await llmClient.generate(prompt); let spec = extractJsonFromResponse(response); if (!spec) { logger.error('Invalid JSON response from LLM. Attempting to repair...'); const repairPrompt = jsonRepairPrompt.replace('{{invalidJson}}', response); response = await llmClient.generate(repairPrompt); spec = extractJsonFromResponse(response); if (!spec) { logger.error('Failed to repair JSON response. Skipping spec generation.'); return { summary: 'Failed to generate product specification due to invalid LLM response', error: 'JSON parsing failed', completedAt: new Date().toISOString() }; } } // Store spec in context for other agents to use updateContext({ spec }); logger.stop(); logger.success('Generated product spec.'); // Return a condensed summary for the agent output (to avoid duplication) return { summary: `Product specification generated with ${spec.userStories?.length || 0} user stories and ${spec.acceptanceCriteria?.length || 0} acceptance criteria.`, title: spec.title, reasoning: response.includes('<thinking>') ? 'Used chain-of-thought reasoning' : 'Direct specification generation', completedAt: new Date().toISOString() }; };