diff --git a/agent_service/agents/base_agent.py b/agent_service/agents/base_agent.py index 71faf64..07b1c25 100644 --- a/agent_service/agents/base_agent.py +++ b/agent_service/agents/base_agent.py @@ -81,6 +81,7 @@ class BaseAgent(ABC): required_odoo_module: str = 'base' system_prompt_file: str = '' tools: list = [] + auto_rag: bool = True # set False on knowledge-only agents to prevent self-calls def __init__(self, odoo, llm, peer_bus=None): self._odoo = odoo @@ -92,6 +93,34 @@ class BaseAgent(ABC): validate_agent_tools(self.tools, self.name) self._validator = ToolCallValidator(self.tools) + async def _lookup_odoo_context(self) -> str: + """ + Auto-fetch Odoo 18 workflow guidance from odoo_doc_agent via PeerBus. + Result is stored in self._gathered['odoo_context'] and injected into + every _loop() LLM call so agents reason with correct Odoo steps. + Returns empty string if unavailable (non-fatal). + """ + if not self.auto_rag or not self._peer_bus or not self._directive: + return '' + module = self.domain if self.domain not in ('base', 'documentation') else None + try: + response = await self._peer_bus.request( + from_agent=self.name, + to_agent='odoo_doc_agent', + request_type='query_docs', + params={ + 'question': self._directive.task, + 'module': module, + 'top_k': 4, + }, + reason='auto workflow guidance lookup', + ) + if response.available and response.success: + return response.data.get('answer', '') + except Exception as exc: + logger.debug('agent=%s auto-RAG skipped: %s', self.name, exc) + return '' + async def execute(self, directive: AgentDirective) -> AgentReport: self._directive = directive self._gathered = {} @@ -99,6 +128,10 @@ class BaseAgent(ABC): t0 = time.monotonic() try: await self._receive(directive) + odoo_ctx = await self._lookup_odoo_context() + if odoo_ctx: + self._gathered['odoo_context'] = odoo_ctx + logger.info('agent=%s odoo_context=%d chars injected', self.name, len(odoo_ctx)) plan = await self._plan() await self._gather(plan) reasoning = await self._reason() @@ -164,6 +197,19 @@ class BaseAgent(ABC): async def _loop(self, messages, tools=None, max_iter=10) -> str: current = list(messages) + + # Inject Odoo workflow context retrieved during execute() + odoo_ctx = self._gathered.get('odoo_context', '') + if odoo_ctx: + inject = [ + {'role': 'user', 'content': f'## Odoo 18 Workflow Reference\n\n{odoo_ctx}'}, + {'role': 'assistant', 'content': 'Understood. I will follow the documented Odoo 18 workflow steps.'}, + ] + if current and current[0].get('role') == 'system': + current = [current[0]] + inject + current[1:] + else: + current = inject + current + active_tools = tools or self.tools for iteration in range(max_iter): resp = await self._llm.submit(current, tools=active_tools, caller=self.name) diff --git a/agent_service/agents/odoo_doc_agent.py b/agent_service/agents/odoo_doc_agent.py index 8d46139..1841f6a 100644 --- a/agent_service/agents/odoo_doc_agent.py +++ b/agent_service/agents/odoo_doc_agent.py @@ -30,6 +30,7 @@ class OdooDocAgent(BaseAgent): required_odoo_module = 'base' system_prompt_file = '' tools = [] + auto_rag = False # prevent self-referential PeerBus calls async def _plan(self) -> dict: return {