""" Engineering Knowledge Assistant: IBM Bob as a repository-aware Q&A engine. """ from __future__ import annotations from core.watsonx import watsonx_generate from utils.cache import repo_cache from utils.context_builder import build_qa_context async def answer_engineering_question(repo_id: str, question: str, chat_history: list | None = None) -> dict: """Use IBM Bob to answer repository-specific engineering questions.""" if repo_id not in repo_cache: raise ValueError("Repository not loaded. Please ingest a repository first.") chat_history = chat_history or [] repo_data = repo_cache[repo_id] context = build_qa_context(repo_data, question) history_str = "\n".join( f"{'Engineer' if message.get('role') == 'user' else 'CodeAtlas'}: {message.get('content', '')}" for message in chat_history[-4:] ) prompt = f"""You are CodeAtlas, an expert engineering intelligence system analyzing a real codebase. You have deep knowledge of this repository's architecture, business logic, and code structure. REPOSITORY INTELLIGENCE: {context} CONVERSATION HISTORY: {history_str} ENGINEER'S QUESTION: {question} Provide a precise, technical answer that: 1. Directly answers the question with specific file paths, function names, and code locations 2. Explains the implementation approach and business logic 3. Identifies related components or dependencies 4. Flags risks or important considerations 5. Suggests next files to explore if relevant Use this format: ANSWER: [Direct answer] IMPLEMENTATION: [How it's implemented with specific locations] RELATED: [Related components/files] RISKS: [Any concerns or gotchas] ###END###""" response = await watsonx_generate( prompt, max_tokens=1200, use_code_model=True, working_dir=repo_data.get("repo_path"), ) sections = {"answer": "", "implementation": "", "related": "", "risks": ""} current = "answer" for line in response.split("\n"): stripped = line.strip() if stripped.startswith("ANSWER:"): current = "answer" sections[current] = stripped[7:].strip() elif stripped.startswith("IMPLEMENTATION:"): current = "implementation" sections[current] = stripped[15:].strip() elif stripped.startswith("RELATED:"): current = "related" sections[current] = stripped[8:].strip() elif stripped.startswith("RISKS:"): current = "risks" sections[current] = stripped[6:].strip() elif stripped and not stripped.startswith("###"): sections[current] = f"{sections[current]} {stripped}".strip() return { "question": question, "answer": sections["answer"].strip() or response.strip(), "implementation": sections["implementation"].strip(), "related": sections["related"].strip(), "risks": sections["risks"].strip(), "full_response": response, }