{"record":{"id":"f72f9f4ddee6d5bf","repo":"HKUDS/DeepTutor","slug":"codegeneratoragent-retry-prompts-are-not-configure","errorCode":null,"errorMessage":"CodeGeneratorAgent retry prompts are not configured.","messagePattern":"CodeGeneratorAgent retry prompts are not configured\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"deeptutor/agents/math_animator/agents/code_generator_agent.py","lineNumber":106,"sourceCode":"        ):\n            _chunks.append(_c)\n        response = \"\".join(_chunks)\n        return GeneratedCode.model_validate(extract_json_object(response))\n\n    async def repair(\n        self,\n        *,\n        user_input: str,\n        output_mode: str,\n        current_code: str,\n        error_message: str,\n        attempt: int,\n        duration_target_seconds: float | None = None,\n    ) -> GeneratedCode:\n        system_prompt = self.get_prompt(\"retry_system\")\n        user_template = self.get_prompt(\"retry_user_template\")\n        if not system_prompt or not user_template:\n            raise ValueError(\"CodeGeneratorAgent retry prompts are not configured.\")\n\n        user_prompt = user_template.format(\n            user_input=user_input.strip(),\n            output_mode=output_mode,\n            attempt=attempt,\n            duration_requirement=(\n                f\"目标时长约 {duration_target_seconds:.1f} 秒，修复后仍需保持接近该时长。\"\n                if duration_target_seconds is not None\n                else \"无明确目标时长。\"\n            ),\n            error_message=build_repair_error_message(error_message),\n            current_code=current_code,\n        )\n        _chunks: list[str] = []\n        async for _c in self.stream_llm(\n            user_prompt=user_prompt,\n            system_prompt=system_prompt,\n            response_format={\"type\": \"json_object\"},","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/agents/math_animator/agents/code_generator_agent.py#L88-L124","documentation":"Raised by the pypdf fallback branch of _extract_pdf when reader.is_encrypted is true. It mirrors the pymupdf branch: pypdf cannot extract text from an encrypted PDF without a password, so a CorruptDocumentError with the filename is raised.","triggerScenarios":"Environment has pypdf but not pymupdf, and the PDF passed to extract_text_from_bytes has encryption enabled with a non-empty user password.","commonSituations":"Same encrypted-document ingestion scenarios as the fitz branch, but in slim environments where only pypdf is installed.","solutions":["Decrypt with pikepdf or qpdf before extraction","Provide the password, decrypt via pypdf's reader.decrypt(pw), re-serialize, then extract","Skip encrypted PDFs during batch ingestion with a logged warning"],"exampleFix":"// before\nreader = PdfReader(io.BytesIO(data))\nif getattr(reader, \"is_encrypted\", False):\n    raise CorruptDocumentError(...)\n\n// after\nreader = PdfReader(io.BytesIO(data))\nif reader.is_encrypted:\n    reader.decrypt(pw)  # or pre-decrypt with pikepdf\npages = [p.extract_text() for p in reader.pages]","handlingStrategy":"try-catch","validationCode":"from pypdf import PdfReader\nimport io\ntry:\n    r = PdfReader(io.BytesIO(data))\n    encrypted = bool(getattr(r, \"is_encrypted\", False))\nexcept Exception:\n    encrypted = False\nif encrypted:\n    request_password_or_skip()","typeGuard":null,"tryCatchPattern":"except CorruptDocumentError as e:\n    if \"encrypted\" in str(e):\n        skip_file_with_reason(fn, \"encrypted PDF\")","preventionTips":["Probe encryption at upload; decrypt with pikepdf before storage","Keep decrypted copies only if policy allows"],"tags":["pdf","encryption","pypdf","document-extraction"],"backgroundTag":"encrypted-pdf-password","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}