from __future__ import annotations import logging import httpx from .base_agent import BaseAgent, AgentReport, SweepReport logger = logging.getLogger(__name__) RAG_URL = "http://192.168.2.9:8000" RAG_TIMEOUT = 60 class OdooDocAgent(BaseAgent): """ Read-only knowledge agent backed by the odootrain RAG stack. Answers questions about Odoo 18 workflows using the indexed documentation. Other agents query it via PeerBus: response = await self._peer_bus.request( from_agent=self.name, to_agent='odoo_doc_agent', request_type='query_docs', params={'question': '...', 'module': 'accounting'}, # module optional reason='Need Odoo workflow guidance', ) guidance = response.data.get('answer', '') """ name = 'odoo_doc_agent' domain = 'documentation' required_odoo_module = 'base' system_prompt_file = '' tools = [] async def _plan(self) -> dict: return { 'question': self._directive.task, 'module': self._directive.params.get('module'), 'top_k': self._directive.params.get('top_k', 6), } async def _gather(self, plan: dict) -> None: payload = { 'question': plan['question'], 'top_k': plan['top_k'], } if plan.get('module'): payload['module'] = plan['module'] try: async with httpx.AsyncClient(timeout=RAG_TIMEOUT) as client: resp = await client.post(f"{RAG_URL}/ask", json=payload) resp.raise_for_status() self._gathered = resp.json() except Exception as exc: logger.error('odoo_doc_agent RAG call failed: %s', exc) self._gathered = {'answer': '', 'sources': [], 'error': str(exc)} async def _reason(self) -> dict: return {} async def _act(self, reasoning: dict) -> None: pass async def _report(self) -> AgentReport: answer = self._gathered.get('answer', '') sources = self._gathered.get('sources', []) error = self._gathered.get('error') status = 'failed' if error and not answer else 'complete' summary = answer or f'RAG lookup failed: {error}' return AgentReport( directive_id=self._directive.directive_id, agent=self.name, status=status, summary=summary, data={ 'answer': answer, 'sources': sources, 'model': self._gathered.get('model', ''), }, error=error, ) async def handle_peer_request(self, request_type: str, params: dict, directive_id: str) -> dict: if request_type != 'query_docs': return {'success': False, 'error': f'Unknown request type: {request_type}'} question = params.get('question', '') if not question: return {'success': False, 'error': 'question is required'} payload = {'question': question, 'top_k': params.get('top_k', 6)} if params.get('module'): payload['module'] = params['module'] try: async with httpx.AsyncClient(timeout=RAG_TIMEOUT) as client: resp = await client.post(f"{RAG_URL}/ask", json=payload) resp.raise_for_status() data = resp.json() return { 'success': True, 'answer': data.get('answer', ''), 'sources': data.get('sources', []), } except Exception as exc: logger.error('odoo_doc_agent peer request failed: %s', exc) return {'success': False, 'error': str(exc)} async def sweep(self) -> SweepReport: try: async with httpx.AsyncClient(timeout=10) as client: resp = await client.get(f"{RAG_URL}/health") health = resp.json() qdrant_ok = 'ok' in str(health.get('qdrant', '')) ollama_ok = 'ok' in str(health.get('ollama', '')) findings = [] if not qdrant_ok: findings.append({'issue': 'Qdrant unhealthy', 'severity': 'high', 'detail': health}) if not ollama_ok: findings.append({'issue': 'Ollama unhealthy', 'severity': 'high', 'detail': health}) return SweepReport(agent=self.name, findings=findings) except Exception as exc: return SweepReport( agent=self.name, findings=[{'issue': 'RAG API unreachable', 'severity': 'high', 'detail': str(exc)}], )