Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/pyob/entrance.py
Original file line number Diff line number Diff line change
Expand Up @@ -535,11 +535,12 @@ def update_ledger_for_file(self, rel_path: str, code: str):
elif isinstance(n.func, ast.Attribute):
potential_refs.add(n.func.attr)
elif isinstance(n, ast.Name) and isinstance(n.ctx, ast.Load):
potential_refs.add(n.id)
if n.id not in ["self", "None", "True", "False"]:
potential_refs.add(n.id)
except Exception as e:
logger.warning(f"Failed to parse Python AST for {rel_path}: {e}")
potential_refs.update(
re.findall(r"\b[a-zA-Z_][a-zA-Z0-9_]{3,}\b", code)
re.findall(r"\b[a-zA-Z_][a-zA-Z0-9_]{4,}\b", code)
)
elif ext in [".js", ".ts"]:
defs = re.findall(
Expand Down
4 changes: 2 additions & 2 deletions src/pyob/prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ def validate_prompts(prompts: Dict[str, str]) -> None:
"PP.md": "You are an elite PYOB Software Engineer. Analyze the code for bugs or architectural gaps.\n\n{memory_section}{ruff_section}{mypy_section}{custom_issues_section}### Source Code:\n```{lang_tag}\n{content}\n```\n\n### CRITICAL RULES:\n1. **ITERATION BUDGET**:\n - IF iteration < 5: Focus ONLY on bug fixes. Do NOT refactor.\n2. **SURGICAL FIXES**: Every <SEARCH> block must be exactly 2-5 lines. Only provide ONE <EDIT> block. Do NOT repeat the entire file.\n3. **STRICT TYPING (PYTHON ONLY)**: If the target file is Python, it uses strict mypy. Every new or modified function MUST have complete argument and return type hints (e.g., `def foo(x: int) -> str:`). For HTML/JavaScript/CSS files, do NOT use type annotations or TypeScript syntax.\n4. **EXTERNAL IMPORTS (PYTHON ONLY)**: If the target file is Python and you import a third-party library that gets a `[no-any-unimported]` error, you MUST append `# type: ignore` to that import statement.\n5. **NO HALLUCINATIONS**: If the code is functional, state 'The code looks good.'\n6. **NO CHATTER**: Be brief. Do not explain things unless necessary.\n7. **SYMBOL SAFETY (MANDATORY)**: The following symbols in this file are referenced by OTHER files in this project. You MUST NOT rename them, change their signatures, or remove them: {symbol_safety_list}\n If you believe a rename would help clarity, output a # TODO comment only. Never rename.\n8. **INTERFACE PRESERVATION**: All public function signatures must remain identical. You may change internals freely. You may NOT change parameter names, counts, or return types of any existing public function.\n9. **FRONTEND LAYOUT & CONTROLS SAFETY**: For HTML/CSS/JS files: (a) Ensure CSS selectors match the exact IDs/classes in the HTML. (b) Never set `overflow: hidden;` on elements where inner shadows/glows must be visible. (c) If a wrapper container has `overflow-y: auto` or `scroll`, bind scroll listeners and scroll actions to that container element instead of `window`.\n10. **STRICT INDENTATION (CRITICAL)**: You MUST use perfect 4-space indentation for all Python code. NEVER use raw tab characters. Match the absolute indentation level of the surrounding code block exactly.\n11. **NO SINGLE-LINE COLONS**: Never put statements on the same line as a colon (e.g., do NOT write 'if x: continue' or 'except: pass'). Always put the statement on a new, indented line.\n\n### HOW TO RESPOND:\n<THOUGHT>\nSummary: ...\nAction: ...\n</THOUGHT>\n<EDIT>\n<SEARCH>\n...\n</SEARCH>\n<REPLACE>\n...\n</REPLACE>\n</EDIT>",
"ALF.md": "You are an elite developer fixing syntax errors.\nThe file `{rel_path}` failed validation with these exact errors:\n{err_text}\n\n### Current Code:\n```\n{code}\n```\n\n### Instructions:\n1. Fix the syntax errors (like stray brackets, unexpected tokens, or indentation) using surgical XML edits.\n2. Respond EXCLUSIVELY with a <THOUGHT> block followed by ONE OR MORE <EDIT> blocks.\n3. Ensure your edits use perfect absolute 4-space indentation and perfectly align with the surrounding brackets. NEVER use raw tab characters.",
"FRE.md": "You are an elite PYOB developer fixing runtime crashes.\n{memory_section}The application crashed during a test run.\n\n### Crash Logs & Traceback:\n{logs}\n\nThe traceback indicates the error occurred in `{rel_path}`.\n\n### Current Code of `{rel_path}`:\n```python\n{code}\n```\n\n### Instructions:\n1. Identify the EXACT root cause of the crash.\n2. Fix the error using surgical XML edits.\n3. Respond EXCLUSIVELY with a <THOUGHT> block followed by ONE OR MORE <EDIT> blocks.\n\n### REQUIRED XML FORMAT:\n<THOUGHT>\nExplanation of root cause...\nImports Needed: [List new imports required or 'None']\n</THOUGHT>\n<EDIT>\n<SEARCH>\nExact lines to replace\n</SEARCH>\n<REPLACE>\nNew replacement lines\n</REPLACE>\n</EDIT>",
"PF.md": 'You are the PYOB Product Architect. Review the source code and suggest ONE highly useful, INTERACTIVE feature.\n\n{memory_section}### Source Code ({lang_name}):\n```{lang_tag}\n{content}\n```\n\n### CRITICAL RULES:\n1. Suggest ONE INTERACTIVE feature relevant to the file\'s language ({lang_name}).\n2. **PYTHON ONLY — ARCHITECTURAL SPLIT**: If the language is Python AND the source is over 800 lines, propose splitting a logical module into a new `.py` file instead of a feature. Use <CREATE_FILE path="new_filename.py">[code]</CREATE_FILE> inside <SNIPPET>.\n3. **PYTHON ONLY — STRICT TYPING**: For Python files only, all new code MUST include strict type hints.\n4. **HTML/JS/CSS**: For frontend files, propose UI/UX enhancements — new interactive elements, improved user flow, animations, or data visualisations. Do NOT suggest Python-style type hints or file splits.\n5. MULTI-FILE ORCHESTRATION: In your <THOUGHT>, list any other files that will need updating.\n6. **NO PREAMBLE**: Do NOT explain what you are about to do before outputting XML. Output ONLY the XML blocks.\n\n### REQUIRED XML FORMAT (output this and nothing else):\n<THOUGHT>\n[Your reasoning and list of affected files]\n</THOUGHT>\n<SNIPPET>\n[New code snippet or <CREATE_FILE> block]\n</SNIPPET>',
"IF.md": "You are an elite PYOB Implementation Engineer. Implement the APPROVED feature into `{rel_path}`.\n\n{memory_section}### Feature Proposal Details:\n{feature_content}\n\n### Current Source Code:\n```{lang_tag}\n{source_code}\n```\n\n### CRITICAL INSTRUCTIONS:\n1. **SURGICAL EDITS**: <SEARCH> blocks must be 2-5 lines. NEVER output the entire file.\n2. **STRICT TYPING (PYTHON ONLY)**: If the target file is Python, you MUST add explicit type hints to any new variables or functions you create to satisfy `mypy --strict`. For HTML/JavaScript/CSS files, do NOT use type annotations or TypeScript syntax.\n3. **UNFOLLOWED IMPORTS (PYTHON ONLY)**: If the target file is Python and you add a new import for an external library, append `# type: ignore` to it.\n4. **NO MASS DELETIONS**: Do not replace large blocks with small ones without structure.\n5. **NO CHATTER**: Do not explain your code. Just provide the XML blocks.\n6. **SYMBOL SAFETY (MANDATORY)**: The following symbols in this file are referenced by OTHER files in this project. You MUST NOT rename them, change their signatures, or remove them: {symbol_safety_list}\n If you believe a rename would help clarity, output a # TODO comment only. Never rename.\n7. **INTERFACE PRESERVATION**: All public function signatures must remain identical. You may change internals freely. You may NOT change parameter names, counts, or return types of any existing public function.\n8. **FRONTEND LAYOUT & CONTROLS SAFETY**: For HTML/CSS/JS files: (a) Ensure CSS selectors match the exact IDs/classes in the HTML. (b) Never set `overflow: hidden;` on elements where inner shadows/glows must be visible. (c) If a wrapper container has `overflow-y: auto` or `scroll`, bind scroll listeners and scroll actions to that container element instead of `window`.\n9. **STRICT INDENTATION (CRITICAL)**: You MUST use perfect 4-space indentation for all Python code. NEVER use raw tab characters. Ensure all statements inside your replacement blocks align perfectly with the surrounding code blocks.\n10. **NO SINGLE-LINE COLONS**: Never put statements on the same line as a colon (e.g., do NOT write 'if x: continue' or 'except: pass'). Always put the statement on a new, indented line.\n\n### REQUIRED XML FORMAT:\n<THOUGHT>\n...\n</THOUGHT>\n<EDIT>\n<SEARCH>\n...\n</SEARCH>\n<REPLACE>\n...\n</REPLACE>\n</EDIT>",
"PF.md": 'You are the PYOB Product Architect. Review the source code and suggest ONE highly useful, INTERACTIVE feature.\n\n{memory_section}### Source Code ({lang_name}):\n```{lang_tag}\n{content}\n```\n\n### CRITICAL RULES:\n1. Suggest ONE INTERACTIVE feature relevant to the file\'s language ({lang_name}).\n2. **PYTHON ONLY — ARCHITECTURAL SPLIT**: If the language is Python AND the source is over 800 lines, propose splitting a logical module into a new `.py` file instead of a feature. Use <CREATE_FILE path="new_filename.py">[code]</CREATE_FILE> inside <SNIPPET>.\n3. **PYTHON ONLY — STRICT TYPING**: For Python files only, all new code MUST include strict type hints.\n4. **HTML/JS/CSS**: For frontend files, propose UI/UX enhancements — new interactive elements, improved user flow, animations, or data visualisations. Do NOT suggest Python-style type hints or file splits.\n5. MULTI-FILE ORCHESTRATION: In your <THOUGHT>, list any other files that will need updating.\n6. **NO PREAMBLE**: Do NOT explain what you are about to do before outputting XML. Output ONLY the XML blocks.\n7. **MIGRATION SIGNATURE INTEGRITY**: When proposing an Architectural Split that moves functions (including private/underscore methods) to a new module, you MUST preserve their exact parameter counts, names, and type annotations so that dependent calls in the original file do not break.\n\n### REQUIRED XML FORMAT (output this and nothing else):\n<THOUGHT>\n[Your reasoning and list of affected files]\n</THOUGHT>\n<SNIPPET>\n[New code snippet or <CREATE_FILE> block]\n</SNIPPET>',
"IF.md": "You are an elite PYOB Implementation Engineer. Implement the APPROVED feature into `{rel_path}`.\n\n{memory_section}### Feature Proposal Details:\n{feature_content}\n\n### Current Source Code:\n```{lang_tag}\n{source_code}\n```\n\n### CRITICAL INSTRUCTIONS:\n1. **SURGICAL EDITS**: <SEARCH> blocks must be 2-5 lines. NEVER output the entire file.\n2. **STRICT TYPING (PYTHON ONLY)**: If the target file is Python, you MUST add explicit type hints to any new variables or functions you create to satisfy `mypy --strict`. For HTML/JavaScript/CSS files, do NOT use type annotations or TypeScript syntax.\n3. **UNFOLLOWED IMPORTS (PYTHON ONLY)**: If the target file is Python and you add a new import for an external library, append `# type: ignore` to it.\n4. **NO MASS DELETIONS**: Do not replace large blocks with small ones without structure.\n5. **NO CHATTER**: Do not explain your code. Just provide the XML blocks.\n6. **SYMBOL SAFETY (MANDATORY)**: The following symbols in this file are referenced by OTHER files in this project. You MUST NOT rename them, change their signatures, or remove them: {symbol_safety_list}\n If you believe a rename would help clarity, output a # TODO comment only. Never rename.\n7. **INTERFACE PRESERVATION**: All public function signatures must remain identical. You may change internals freely. You may NOT change parameter names, counts, or return types of any existing public function.\n8. **FRONTEND LAYOUT & CONTROLS SAFETY**: For HTML/CSS/JS files: (a) Ensure CSS selectors match the exact IDs/classes in the HTML. (b) Never set `overflow: hidden;` on elements where inner shadows/glows must be visible. (c) If a wrapper container has `overflow-y: auto` or `scroll`, bind scroll listeners and scroll actions to that container element instead of `window`.\n9. **STRICT INDENTATION (CRITICAL)**: You MUST use perfect 4-space indentation for all Python code. NEVER use raw tab characters. Ensure all statements inside your replacement blocks align perfectly with the surrounding code blocks.\n10. **NO SINGLE-LINE COLONS**: Never put statements on the same line as a colon (e.g., do NOT write 'if x: continue' or 'except: pass'). Always put the statement on a new, indented line.\n11. **MIGRATION SIGNATURE INTEGRITY**: When implementing an Architectural Split, you MUST preserve the exact parameter counts, names, and type annotations of all migrated functions (including private/underscore methods) so that dependent calls in the original file do not break.\n\n### REQUIRED XML FORMAT:\n<THOUGHT>\n...\n</THOUGHT>\n<EDIT>\n<SEARCH>\n...\n</SEARCH>\n<REPLACE>\n...\n</REPLACE>\n</EDIT>",
"PCF.md": 'You are the PYOB Symbolic Fixer taking over Phase 3 Cascaded Edits.\n{memory_section}We just modified `{trigger_file}`, and it broke a dependency downstream: `{rel_broken_path}`.\n\n### Linter Errors for `{rel_broken_path}`:\n{mypy_errors}\n\n### Source Code of `{rel_broken_path}`:\n```python\n{broken_code}\n```\n\n### Instructions:\n1. Respond EXCLUSIVELY with a <THOUGHT> block followed by ONE <EDIT> block to fix the broken references.\n2. **DEFEATING MYPY (PYTHON ONLY)**: If the file is Python and the error contains `[union-attr]` or states `Item "None" of ... has no attribute`, adding a type hint will fail. You MUST fix this by either inserting `assert variable is not None` before the operation, or adding `# type: ignore` to the end of the failing line.\n3. **UNIMPORTED ERRORS (PYTHON ONLY)**: If the file is Python and the error is `[no-any-unimported]`, you MUST append `# type: ignore` to the import statement causing it.\n4. **STRICT INDENTATION**: You MUST use perfect 4-space indentation for all Python code. NEVER use raw tab characters. Match the exact indentation level of the surrounding code.\n\n### REQUIRED XML FORMAT:\n<THOUGHT>\nExplanation of cascade fix...\n</THOUGHT>\n<EDIT>\n<SEARCH>\nExact lines to replace\n</SEARCH>\n<REPLACE>\nNew replacement lines\n</REPLACE>\n</EDIT>',
"PIR.md": "You are an elite PYOB developer performing a post-implementation repair.\nAn automated attempt to implement a feature or bugfix has failed, resulting in the following errors.\n\n### Original Goal / Change Request:\n{context_of_change}\n\n### The Resulting Errors (Linter/Runtime):\n{err_text}\n\n### The Broken Code in `{rel_path}`:\n```\n{code}\n```\n\n### Instructions:\n1. Analyze the 'Original Goal' and the 'Resulting Errors' together.\n2. CRITICAL IMPORT CHECK (PYTHON ONLY): If the file is Python and the error is `F821 Undefined name`, you MUST create an <EDIT> block at the top of the file to add the missing `import` statement.\n3. **DEFEATING MYPY [no-any-unimported] (PYTHON ONLY)**: If the file is Python and the error says `due to an unfollowed import [no-any-unimported]`, you MUST locate the import statement for that library and append `# type: ignore` to the end of that line.\n4. **DEFEATING MYPY [union-attr] (PYTHON ONLY)**: If the file is Python and the error is a `[union-attr]` or `None` type error, insert `assert object is not None` right before it is used, or append `# type: ignore` to the failing line.\n5. **CRITICAL INDENTATION CHECK**: If the error mentions indentation or unindent, you MUST rewrite the <EDIT> block using perfect absolute 4-space indentation. NEVER use raw tab characters. Ensure every line aligns perfectly with the adjacent untouched code lines.\n6. Create a surgical XML edit to fix the code.\n\n### REQUIRED XML FORMAT:\n<THOUGHT>\nRoot Cause: ...\nImports Needed: ...\nAction: ...\n</THOUGHT>\n<EDIT>\n<SEARCH>\nExact lines to replace\n</SEARCH>\n<REPLACE>\nNew replacement lines\n</REPLACE>\n</EDIT>",
}
12 changes: 7 additions & 5 deletions src/pyob/pyob_code_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,29 @@ def visit_Import(self, node: ast.Import) -> None:
except Exception:
pass

def visit_ImportFrom(self, node):
def visit_ImportFrom(self, node: ast.ImportFrom) -> None:
try:
self.imports.append(ast.unparse(node))
except Exception:
pass

def visit_ClassDef(self, node):
def visit_ClassDef(self, node: ast.ClassDef) -> None:
self.classes.append(f"class {node.name}")
old_class = self.current_class
self.current_class = node.name
for child in node.body:
self.visit(child)
self.current_class = old_class

def visit_FunctionDef(self, node):
def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
self.handle_function(node)

def visit_AsyncFunctionDef(self, node):
def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None:
self.handle_function(node)

def handle_function(self, node):
def handle_function(
self, node: ast.FunctionDef | ast.AsyncFunctionDef
) -> None:
args = []
for arg in node.args.args:
if self.current_class and arg.arg == "self":
Expand Down
Loading