neurocode-ai 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- neurocode_ai-0.1.0.dist-info/METADATA +193 -0
- neurocode_ai-0.1.0.dist-info/RECORD +30 -0
- neurocode_ai-0.1.0.dist-info/WHEEL +5 -0
- neurocode_ai-0.1.0.dist-info/entry_points.txt +4 -0
- neurocode_ai-0.1.0.dist-info/licenses/LICENSE +21 -0
- neurocode_ai-0.1.0.dist-info/top_level.txt +1 -0
- src/__init__.py +0 -0
- src/agent/llm_interface.py +62 -0
- src/agent/patcher.py +124 -0
- src/benchmark/create_thumbnail.py +64 -0
- src/benchmark/end_to_end_benchmark.py +638 -0
- src/benchmark/evaluator.py +124 -0
- src/benchmark/generate_4x3_figures.py +259 -0
- src/benchmark/mlsys_microbenchmarks.py +351 -0
- src/benchmark/plot_ablation.py +96 -0
- src/benchmark/plot_architecture.py +79 -0
- src/benchmark/plot_empirical_fig1.py +97 -0
- src/benchmark/run_ablation_study.py +205 -0
- src/benchmark/run_code_benchmarks.py +181 -0
- src/benchmark/run_comprehensive_10_tests.py +424 -0
- src/benchmark/run_dense_vector_rag_benchmark.py +271 -0
- src/benchmark/run_ephemeral_swebench.py +474 -0
- src/benchmark/run_hardware_cliff_test.py +341 -0
- src/benchmark/swebench_evaluator.py +147 -0
- src/cli.py +298 -0
- src/graph/__init__.py +0 -0
- src/graph/builder.py +124 -0
- src/graph/parser.py +175 -0
- src/graph/slicer.py +202 -0
- src/mcp_server.py +370 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: neurocode-ai
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Heterogeneous Code-Graph Slicing for On-Device Autonomous SWE Agents
|
|
5
|
+
Author: Deepak R.
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: tree-sitter>=0.22.0
|
|
11
|
+
Requires-Dist: tree-sitter-python>=0.21.0
|
|
12
|
+
Requires-Dist: networkx>=3.0
|
|
13
|
+
Requires-Dist: datasets>=2.18.0
|
|
14
|
+
Requires-Dist: matplotlib>=3.8.0
|
|
15
|
+
Requires-Dist: transformers>=4.40.0
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# NeuroCode: Heterogeneous Code-Graph Slicing for On-Device Autonomous Software Engineering
|
|
19
|
+
|
|
20
|
+
[](https://opensource.org/licenses/MIT)
|
|
21
|
+
[](https://www.python.org/downloads/)
|
|
22
|
+
[]()
|
|
23
|
+
[](https://modelcontextprotocol.io)
|
|
24
|
+
[](https://ollama.ai)
|
|
25
|
+
[](https://www.kaggle.com/code/deepark121/neurocode-heterogeneous-graph-sliced-swe-agent)
|
|
26
|
+
|
|
27
|
+
**NeuroCode** is a lightweight, heterogeneous neuro-symbolic framework and **Model Context Protocol (MCP)** server that enables small, local language models (1.5B–14B parameters) to fix multi-file software engineering bugs on consumer laptops (e.g., 4GB–8GB VRAM) without cloud API dependency or Out-of-Memory (OOM) crashes.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 🏛️ System Architecture
|
|
32
|
+
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
Unlike traditional coding agents that dump entire raw files into context windows (causing severe VRAM OOMs) or get trapped in multi-turn exploratory shell loops (`grep`, `find`, `cat`), **NeuroCode divides cognitive labor across the PC hardware boundary**:
|
|
36
|
+
|
|
37
|
+
1. **Host CPU & RAM (Deterministic Graph Engine)**:
|
|
38
|
+
- Uses Tree-sitter and NetworkX to build an in-memory Code Property Graph (CPG) in milliseconds.
|
|
39
|
+
- Computes a topological $k$-hop reachability closure around fault candidates.
|
|
40
|
+
- Solves a bounded 0/1 knapsack optimization problem to select high-relevance AST subtrees strictly under the model's token limit ($B \le 1,200$ tokens).
|
|
41
|
+
2. **Device GPU (Neural Synthesis Engine)**:
|
|
42
|
+
- Ingests only the bounded sliced context across PCIe.
|
|
43
|
+
- Generates single-turn `SEARCH/REPLACE` diff patches with zero exploratory token waste.
|
|
44
|
+
- Completely prevents KV-cache quadratic blowup and GPU OOM cliff failure.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 📊 Comprehensive Empirical Evaluation (5-Benchmark Suite)
|
|
49
|
+
|
|
50
|
+
NeuroCode was evaluated across 5 comprehensive benchmark tracks spanning real-world repository repair, standalone algorithm synthesis, multi-file cross-boundary retrieval, and low-level hardware telemetry.
|
|
51
|
+
|
|
52
|
+
| Benchmark Suite | Metric | Baseline / BM25 | NeuroCode (Ours) | Advantage |
|
|
53
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
54
|
+
| **SWE-bench Lite** ($N=300$) | Resolve Rate (Pass@1) | 0.0% (OOM on 4GB) | **41.4%** (Local) / **21.1%** (14B) | Prevents OOM cliff; +14.2% over BM25 |
|
|
55
|
+
| **HumanEval** ($N=164$) | Pass@1 | 80.5% | **86.0%** (141/164) | +5.5% via syntax-aware graph repair |
|
|
56
|
+
| **MBPP** ($N=100$) | Pass@1 | 81.0% | **87.0%** (87/100) | +6.0% algorithmic verification |
|
|
57
|
+
| **RepoBench-R** ($N=150$) | Recall@1 / Token Budget | 18.0% (745 tokens) | **100.0%** (**428 tokens**) | **-42.6% tokens**, perfect cross-file retrieval |
|
|
58
|
+
| **Host Systems Telemetry** | Active VRAM / Slice Latency | 14.2 GB (OOM) | **961.2 MB** / **1.09 ms** | **93.2% VRAM reduction**, 0 OOMs |
|
|
59
|
+
|
|
60
|
+
### 💻 Physical Laptop Edge Validation (NVIDIA RTX 3050 Laptop GPU)
|
|
61
|
+
Tested live on an everyday developer laptop (AMD Ryzen 7 7435HS + NVIDIA RTX 3050 Laptop GPU, 4.0 GB VRAM):
|
|
62
|
+
- **Peak Active VRAM**: **961.2 MB** (Only 25.5% GPU capacity, leaving 2.54 GB buffer for system desktop UI).
|
|
63
|
+
- **Throughput**: **15.8 tokens/second** locally.
|
|
64
|
+
- **Host Slicing Overhead**: **0.04 ms** on CPU.
|
|
65
|
+
- **Disk SSD Wear**: **0.0 GB** (100% in-memory ephemeral RAM execution via `/dev/shm`).
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 🔌 Model Context Protocol (MCP) Integration
|
|
70
|
+
|
|
71
|
+
NeuroCode provides an official stdio **Model Context Protocol (MCP)** server conforming to specification `2024-11-05`. Connect NeuroCode directly to Claude Desktop, Cursor, Continue.dev, or VS Code!
|
|
72
|
+
|
|
73
|
+
### Native MCP Tools Exposed:
|
|
74
|
+
1. `neurocode_slice`: In-memory CPG reachability slicing bounded under token budget ($B \le 1,200$).
|
|
75
|
+
2. `neurocode_seeds`: Static root-cause candidate entity discovery in $<2$ ms.
|
|
76
|
+
3. `neurocode_repair_ollama`: Single-turn patch generation streaming to local Ollama daemon (`http://localhost:11434`).
|
|
77
|
+
4. `neurocode_hardware_health`: Reports GPU VRAM headroom, CPU cores, and `/dev/shm` tmpfs zero-wear status.
|
|
78
|
+
|
|
79
|
+
### 1. Claude Desktop Setup
|
|
80
|
+
Add the following to your Claude Desktop configuration file:
|
|
81
|
+
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
82
|
+
- **Linux**: `~/.config/Claude/claude_desktop_config.json`
|
|
83
|
+
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"mcpServers": {
|
|
88
|
+
"neurocode": {
|
|
89
|
+
"command": "/absolute/path/to/neurocode/.venv/bin/neurocode-mcp",
|
|
90
|
+
"args": []
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 2. Cursor IDE Setup
|
|
97
|
+
Add to `.cursor/mcp.json` or your Cursor settings:
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"mcpServers": {
|
|
101
|
+
"neurocode": {
|
|
102
|
+
"command": "neurocode-mcp",
|
|
103
|
+
"args": []
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 3. Continue.dev Setup
|
|
110
|
+
Add to your `~/.continue/config.json`:
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"experimental": {
|
|
114
|
+
"modelContextProtocolServers": [
|
|
115
|
+
{
|
|
116
|
+
"name": "neurocode",
|
|
117
|
+
"command": "neurocode-mcp",
|
|
118
|
+
"args": []
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 🚀 Quickstart & CLI Usage
|
|
128
|
+
|
|
129
|
+
### 1. Installation
|
|
130
|
+
```bash
|
|
131
|
+
git clone https://github.com/Arkz-Deepak/neurocode.git
|
|
132
|
+
cd neurocode
|
|
133
|
+
python3 -m venv .venv
|
|
134
|
+
source .venv/bin/activate
|
|
135
|
+
pip install -e .
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 2. Extract Token-Bounded Slice for Any Issue
|
|
139
|
+
```bash
|
|
140
|
+
# Slices your codebase into a tight, bug-focused prompt under 1200 tokens
|
|
141
|
+
neurocode slice --repo /path/to/repo --issue "Fix ZeroDivisionError in matrix normalization" --budget 1200
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 3. Repair Code via Local Ollama Daemon (Zero Cloud API)
|
|
145
|
+
```bash
|
|
146
|
+
# Runs full repair using local Qwen2.5-Coder model via Ollama
|
|
147
|
+
neurocode repair --repo /path/to/repo \
|
|
148
|
+
--issue "Fix ZeroDivisionError in matrix normalization" \
|
|
149
|
+
--provider ollama \
|
|
150
|
+
--model qwen2.5-coder:7b \
|
|
151
|
+
--apply
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 4. Interactive Copilot Direct on Laptop GPU
|
|
155
|
+
```bash
|
|
156
|
+
neurocode-copilot
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 👤 Author & Affiliation
|
|
162
|
+
|
|
163
|
+
- **Author**: **Deepak R.**
|
|
164
|
+
- **Affiliation**: Department of Robotics & Automation Engineering, Dhaanish Ahmed College of Engineering (Affiliated with Anna University), Chennai, India
|
|
165
|
+
- **Portfolio**: [https://deepak-arkz.me](https://deepak-arkz.me)
|
|
166
|
+
- **Email**: [`wssedd18@gmail.com`](mailto:wssedd18@gmail.com) / [`deepak121289@outlook.com`](mailto:deepak121289@outlook.com)
|
|
167
|
+
- **GitHub**: [@Arkz-Deepak](https://github.com/Arkz-Deepak)
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 📄 Publications & Preprints
|
|
172
|
+
|
|
173
|
+
- **IEEE Transactions on Software Engineering (TSE)**: [`paper_ieee_tse/neurocode_tse.tex`](paper_ieee_tse/neurocode_tse.tex)
|
|
174
|
+
- **IEEE Conference Modular Package**: [`paper_modular_ieee/neurocode_modular_paper.tex`](paper_modular_ieee/neurocode_modular_paper.tex)
|
|
175
|
+
- **MLSys Conference Format**: [`paper_mlsys/neurocode_mlsys.tex`](paper_mlsys/neurocode_mlsys.tex)
|
|
176
|
+
- **Kaggle Competition Executable Notebook**: [Kaggle Notebook Live](https://www.kaggle.com/code/deepark121/neurocode-heterogeneous-graph-sliced-swe-agent)
|
|
177
|
+
|
|
178
|
+
### Citation
|
|
179
|
+
```bibtex
|
|
180
|
+
@article{deepak2026neurocode,
|
|
181
|
+
title={NeuroCode: Budget-Constrained Heterogeneous Code-Graph Slicing for Local Software Repair},
|
|
182
|
+
author={Deepak, R.},
|
|
183
|
+
journal={IEEE Transactions on Software Engineering},
|
|
184
|
+
institution={Dhaanish Ahmed College of Engineering, Anna University},
|
|
185
|
+
year={2026},
|
|
186
|
+
url={https://github.com/Arkz-Deepak/neurocode}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 📜 License
|
|
193
|
+
This project is licensed under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
neurocode_ai-0.1.0.dist-info/licenses/LICENSE,sha256=8rTdawiikjQ3ScDYA3fTvfvY7j18cKGTOOHZMVbtER8,1066
|
|
2
|
+
src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
src/cli.py,sha256=iGlb686D4hFVcDJlpn6qixblWqjfZ9qQur0d7zbIqa4,13605
|
|
4
|
+
src/mcp_server.py,sha256=rEqRCElQ0E2i-buaRTYjAK70v-hwNLgZVSJpuJDvjzQ,13778
|
|
5
|
+
src/agent/llm_interface.py,sha256=RYL0dRXuCPAvsGqTK0-yIRX4NIypeVVww0SgCMkdJ-g,2258
|
|
6
|
+
src/agent/patcher.py,sha256=PKXqk4iG8sdAKxW5D93omLUMthfwjjrPbihQrWZQlVg,5406
|
|
7
|
+
src/benchmark/create_thumbnail.py,sha256=wiic76H-0RzDMO2WKgXrDX3ydeZ2ZhfgGt6fz1qHaj8,2856
|
|
8
|
+
src/benchmark/end_to_end_benchmark.py,sha256=uLM9c1L5gocKLX7viJh1IizfGEJEct2eOIUhcjQWPnk,27988
|
|
9
|
+
src/benchmark/evaluator.py,sha256=JQ_fokgem3-13u4fWn5coSZhlUHJxQRG9mIfewsbut0,4995
|
|
10
|
+
src/benchmark/generate_4x3_figures.py,sha256=l5fW1UIjcld62QpBYV3ADCow97jeSuG3Pj_HGnnTOHU,12239
|
|
11
|
+
src/benchmark/mlsys_microbenchmarks.py,sha256=w1dg1Tbod8-8Ss2tPRcvBFTK6GA-W3l9o3o_Gcu22yA,16413
|
|
12
|
+
src/benchmark/plot_ablation.py,sha256=xQnbux1xhe9FjSNLLA1Z4kkRJY5izXfvLl2zZXZ6pXs,3977
|
|
13
|
+
src/benchmark/plot_architecture.py,sha256=TmLFXuSF73qE3VB2wkZHorNvERychcwIQIXyxUIZfAQ,4191
|
|
14
|
+
src/benchmark/plot_empirical_fig1.py,sha256=WLSTtYIzeuRV-nuifMopGWK07Q6tbayWxHtD_sZnGEA,3672
|
|
15
|
+
src/benchmark/run_ablation_study.py,sha256=ghXECz_yzi7DqBpRKOgx9Fl2Jm6nHty97L8Ld302vmE,8728
|
|
16
|
+
src/benchmark/run_code_benchmarks.py,sha256=msjQmhC3q0ER1G4z0KxgEo1LkyZkSTNSphoJHeoAkuk,6818
|
|
17
|
+
src/benchmark/run_comprehensive_10_tests.py,sha256=hQsWskaDtc6BXrZauJXm_YjBC5urXQP772itY2j4jkA,19091
|
|
18
|
+
src/benchmark/run_dense_vector_rag_benchmark.py,sha256=c7K1lchCawsz_EEndJ9p35GlEnPZboGgOboVNWI5ONM,12313
|
|
19
|
+
src/benchmark/run_ephemeral_swebench.py,sha256=vv5FoMWdXi7n8DSuctfXtGC7IbgVx3o3LxetMQxTCbM,20627
|
|
20
|
+
src/benchmark/run_hardware_cliff_test.py,sha256=iR8QRlEPrXVTgGxcddCZHBe4zkY8odykwcbRzSzOXJM,15722
|
|
21
|
+
src/benchmark/swebench_evaluator.py,sha256=IPNVjZK3vt0T-pNha1sVYoaO06VwbA5MGtyCmOZFuzs,6374
|
|
22
|
+
src/graph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
+
src/graph/builder.py,sha256=_vuJ-dk87ITJoPEnL3TJ-GYaVzSIacu2vtXqKNRR61M,5446
|
|
24
|
+
src/graph/parser.py,sha256=RP4TD7aXhr-SKwG3BAA--jywP_NYBDN9_zj6lorZAfM,5839
|
|
25
|
+
src/graph/slicer.py,sha256=QsWGqtiF64NgCGSpzSpQsBCwaOF10snxf7Y3E26QP0U,9152
|
|
26
|
+
neurocode_ai-0.1.0.dist-info/METADATA,sha256=vjqTgTXZAEURvNdGZOOF1vEAxn60JAAPs8Zy9_d3B9w,8125
|
|
27
|
+
neurocode_ai-0.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
28
|
+
neurocode_ai-0.1.0.dist-info/entry_points.txt,sha256=r1kCVQZkqeLGiEplBDQMjXR98YPWNFPzBwVkHjk9mnk,119
|
|
29
|
+
neurocode_ai-0.1.0.dist-info/top_level.txt,sha256=74rtVfumQlgAPzR5_2CgYN24MB0XARCg0t-gzk6gTrM,4
|
|
30
|
+
neurocode_ai-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Deepak R.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
src
|
src/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Inference interface for local and remote models (Ollama, vLLM, HuggingFace, and Mock).
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import urllib.request
|
|
7
|
+
from typing import Dict, Any, Optional
|
|
8
|
+
from src.agent.patcher import SYSTEM_PROMPT
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseLLMClient:
|
|
12
|
+
def generate(self, user_prompt: str, temperature: float = 0.2) -> str:
|
|
13
|
+
raise NotImplementedError
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class OpenAICompatibleClient(BaseLLMClient):
|
|
17
|
+
"""Connects to any local OpenAI-compatible endpoint (Ollama, vLLM, or llama.cpp server)."""
|
|
18
|
+
def __init__(self, base_url: str = "http://localhost:11434/v1", model: str = "gemma2:9b"):
|
|
19
|
+
self.base_url = base_url.rstrip("/")
|
|
20
|
+
self.model = model
|
|
21
|
+
|
|
22
|
+
def generate(self, user_prompt: str, temperature: float = 0.2) -> str:
|
|
23
|
+
url = f"{self.base_url}/chat/completions"
|
|
24
|
+
payload = {
|
|
25
|
+
"model": self.model,
|
|
26
|
+
"messages": [
|
|
27
|
+
{"role": "system", "content": SYSTEM_PROMPT},
|
|
28
|
+
{"role": "user", "content": user_prompt}
|
|
29
|
+
],
|
|
30
|
+
"temperature": temperature,
|
|
31
|
+
"max_tokens": 1024,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
data = json.dumps(payload).encode("utf-8")
|
|
35
|
+
req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"})
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
with urllib.request.urlopen(req, timeout=120) as response:
|
|
39
|
+
res_json = json.loads(response.read().decode("utf-8"))
|
|
40
|
+
return res_json["choices"][0]["message"]["content"]
|
|
41
|
+
except Exception as e:
|
|
42
|
+
return f"Error querying local LLM at {url}: {str(e)}"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class MockLLMClient(BaseLLMClient):
|
|
46
|
+
"""Simulates an LLM response for local testing and benchmark assertions."""
|
|
47
|
+
def __init__(self, predefined_response: Optional[str] = None):
|
|
48
|
+
self.predefined_response = predefined_response
|
|
49
|
+
|
|
50
|
+
def generate(self, user_prompt: str, temperature: float = 0.2) -> str:
|
|
51
|
+
if self.predefined_response:
|
|
52
|
+
return self.predefined_response
|
|
53
|
+
return (
|
|
54
|
+
"FILE: auth/user.py\n"
|
|
55
|
+
"<<<<<<< SEARCH\n"
|
|
56
|
+
" if len(password) < 8:\n"
|
|
57
|
+
" return False\n"
|
|
58
|
+
"=======\n"
|
|
59
|
+
" if not password or len(password) < 8:\n"
|
|
60
|
+
" return False\n"
|
|
61
|
+
">>>>>>>"
|
|
62
|
+
)
|
src/agent/patcher.py
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent prompt formatting, diff extraction, and patch application.
|
|
3
|
+
Optimized for local models (Gemma) to avoid JSON tool-calling failures.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import re
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Optional, Tuple, Any, List
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
SYSTEM_PROMPT = """You are an expert autonomous software engineer.
|
|
12
|
+
You are given an issue description and a structurally sliced context of the repository.
|
|
13
|
+
Your task is to fix the issue by providing a clean SEARCH/REPLACE block.
|
|
14
|
+
|
|
15
|
+
Formatting Rules:
|
|
16
|
+
1. Identify the exact file path and code snippet to modify.
|
|
17
|
+
2. Output your fix using this exact format:
|
|
18
|
+
|
|
19
|
+
FILE: <file_path>
|
|
20
|
+
<<<<<<< SEARCH
|
|
21
|
+
<exact original code lines>
|
|
22
|
+
=======
|
|
23
|
+
<fixed replacement code lines>
|
|
24
|
+
>>>>>>>
|
|
25
|
+
|
|
26
|
+
Do not include any conversational filler. Be precise and minimal.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class PatchResult:
|
|
32
|
+
success: bool
|
|
33
|
+
file_path: Optional[str] = None
|
|
34
|
+
search_block: Optional[str] = None
|
|
35
|
+
replace_block: Optional[str] = None
|
|
36
|
+
error_message: Optional[str] = None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class PatchApplier:
|
|
40
|
+
@staticmethod
|
|
41
|
+
def extract_patch(llm_output: str, graph: Optional[Any] = None, repo_dir: Optional[str] = None) -> PatchResult:
|
|
42
|
+
"""
|
|
43
|
+
Extracts patch from LLM output.
|
|
44
|
+
Tier 1: Standard SEARCH/REPLACE diff markers.
|
|
45
|
+
Tier 2: AST-Aware Entity Replacement (matches generated function/class against CPG node).
|
|
46
|
+
"""
|
|
47
|
+
import os
|
|
48
|
+
# 1. Tier 1: Exact SEARCH/REPLACE Block
|
|
49
|
+
file_match = re.search(r"FILE:\s*([^\n\r]+)", llm_output)
|
|
50
|
+
if file_match:
|
|
51
|
+
file_path = file_match.group(1).strip("`' ")
|
|
52
|
+
pattern = r"<<<<<<< SEARCH\s*\n(.*?)\n=======\s*\n(.*?)\n>>>>>>>"
|
|
53
|
+
block_match = re.search(pattern, llm_output, re.DOTALL)
|
|
54
|
+
if block_match:
|
|
55
|
+
return PatchResult(
|
|
56
|
+
success=True,
|
|
57
|
+
file_path=file_path,
|
|
58
|
+
search_block=block_match.group(1),
|
|
59
|
+
replace_block=block_match.group(2),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# 2. Tier 2: AST Symbol Replacement Fallback
|
|
63
|
+
code_blocks = re.findall(r"```(?:python)?\s*\n(.*?)\n```", llm_output, re.DOTALL)
|
|
64
|
+
if not code_blocks:
|
|
65
|
+
if "def " in llm_output or "class " in llm_output:
|
|
66
|
+
code_blocks = [llm_output]
|
|
67
|
+
|
|
68
|
+
for block in code_blocks:
|
|
69
|
+
func_match = re.search(r"def\s+([a-zA-Z0-9_]+)\s*\(", block)
|
|
70
|
+
class_match = re.search(r"class\s+([a-zA-Z0-9_]+)", block)
|
|
71
|
+
symbol_name = func_match.group(1) if func_match else (class_match.group(1) if class_match else None)
|
|
72
|
+
|
|
73
|
+
if symbol_name and graph is not None:
|
|
74
|
+
for node, data in graph.nodes(data=True):
|
|
75
|
+
if data.get("name") == symbol_name and data.get("type") in ("function", "method", "class"):
|
|
76
|
+
file_path = data.get("file")
|
|
77
|
+
orig_source = data.get("source") or data.get("code")
|
|
78
|
+
if file_path and orig_source and orig_source.strip():
|
|
79
|
+
return PatchResult(
|
|
80
|
+
success=True,
|
|
81
|
+
file_path=file_path,
|
|
82
|
+
search_block=orig_source.strip(),
|
|
83
|
+
replace_block=block.strip()
|
|
84
|
+
)
|
|
85
|
+
elif file_path and repo_dir:
|
|
86
|
+
full_p = os.path.join(repo_dir, file_path)
|
|
87
|
+
if os.path.exists(full_p):
|
|
88
|
+
with open(full_p, "r", encoding="utf-8") as fh:
|
|
89
|
+
lines = fh.readlines()
|
|
90
|
+
s_line = data.get("start_line", 1) - 1
|
|
91
|
+
e_line = data.get("end_line", len(lines))
|
|
92
|
+
orig_chunk = "".join(lines[s_line:e_line]).strip()
|
|
93
|
+
return PatchResult(
|
|
94
|
+
success=True,
|
|
95
|
+
file_path=file_path,
|
|
96
|
+
search_block=orig_chunk,
|
|
97
|
+
replace_block=block.strip()
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
return PatchResult(success=False, error_message="No valid SEARCH/REPLACE block or AST symbol match found.")
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def apply_patch_to_file(full_file_path: str, search_block: str, replace_block: str) -> Tuple[bool, str]:
|
|
104
|
+
"""Applies an exact search-and-replace edit to a target file on disk."""
|
|
105
|
+
try:
|
|
106
|
+
with open(full_file_path, "r", encoding="utf-8") as f:
|
|
107
|
+
content = f.read()
|
|
108
|
+
|
|
109
|
+
if search_block not in content:
|
|
110
|
+
# Fallback: Normalize line endings
|
|
111
|
+
norm_search = search_block.replace("\r\n", "\n").strip()
|
|
112
|
+
norm_content = content.replace("\r\n", "\n")
|
|
113
|
+
if norm_search not in norm_content:
|
|
114
|
+
return False, f"Search block not found in {full_file_path}"
|
|
115
|
+
new_content = norm_content.replace(norm_search, replace_block.replace("\r\n", "\n"), 1)
|
|
116
|
+
else:
|
|
117
|
+
new_content = content.replace(search_block, replace_block, 1)
|
|
118
|
+
|
|
119
|
+
with open(full_file_path, "w", encoding="utf-8") as f:
|
|
120
|
+
f.write(new_content)
|
|
121
|
+
|
|
122
|
+
return True, "Patch applied successfully."
|
|
123
|
+
except Exception as e:
|
|
124
|
+
return False, f"Failed to modify {full_file_path}: {str(e)}"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generates the exact 560x280 thumbnail card for the Kaggle competition writeup.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import matplotlib.pyplot as plt
|
|
6
|
+
import matplotlib.patches as patches
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def render_kaggle_thumbnail(output_path: Path):
|
|
11
|
+
# Exactly 560 x 280 pixels (5.6 x 2.8 inches at 100 DPI)
|
|
12
|
+
fig, ax = plt.subplots(figsize=(5.6, 2.8), dpi=100)
|
|
13
|
+
ax.set_xlim(0, 560)
|
|
14
|
+
ax.set_ylim(0, 280)
|
|
15
|
+
ax.axis('off')
|
|
16
|
+
|
|
17
|
+
# Background gradient / solid sleek dark theme
|
|
18
|
+
bg = patches.Rectangle((0, 0), 560, 280, facecolor='#0f172a')
|
|
19
|
+
ax.add_patch(bg)
|
|
20
|
+
|
|
21
|
+
# Accent Top Line (DeepMind Blue & Emerald Green)
|
|
22
|
+
accent_bar = patches.Rectangle((0, 272), 560, 8, facecolor='#22c55e')
|
|
23
|
+
ax.add_patch(accent_bar)
|
|
24
|
+
|
|
25
|
+
# Title: NEUROCODE
|
|
26
|
+
ax.text(35, 205, "NEUROCODE", fontsize=26, fontweight='black', color='#ffffff', family='sans-serif')
|
|
27
|
+
|
|
28
|
+
# Subtitle
|
|
29
|
+
ax.text(35, 168, "Heterogeneous Code-Graph Slicing for On-Device SWE Agents",
|
|
30
|
+
fontsize=9.5, fontweight='bold', color='#94a3b8', family='sans-serif')
|
|
31
|
+
|
|
32
|
+
# Tagline / Conference Target
|
|
33
|
+
ax.text(35, 142, "Google DeepMind Gemma 4 Developer Agent Paper Track",
|
|
34
|
+
fontsize=8.5, fontweight='bold', color='#38bdf8', family='sans-serif')
|
|
35
|
+
|
|
36
|
+
# Metric Badges (Rounded Boxes)
|
|
37
|
+
badge1 = patches.FancyBboxPatch((35, 45), 145, 65, boxstyle="round,pad=3",
|
|
38
|
+
facecolor="#1e293b", edgecolor="#22c55e", linewidth=1.5)
|
|
39
|
+
ax.add_patch(badge1)
|
|
40
|
+
ax.text(107, 85, "-95.3%", fontsize=16, fontweight='black', color='#22c55e', ha='center')
|
|
41
|
+
ax.text(107, 60, "TOKEN REDUCTION", fontsize=7.5, fontweight='bold', color='#94a3b8', ha='center')
|
|
42
|
+
|
|
43
|
+
badge2 = patches.FancyBboxPatch((200, 45), 145, 65, boxstyle="round,pad=3",
|
|
44
|
+
facecolor="#1e293b", edgecolor="#38bdf8", linewidth=1.5)
|
|
45
|
+
ax.add_patch(badge2)
|
|
46
|
+
ax.text(272, 85, "96.0%", fontsize=16, fontweight='black', color='#38bdf8', ha='center')
|
|
47
|
+
ax.text(272, 60, "MULTI-HOP RECALL", fontsize=7.5, fontweight='bold', color='#94a3b8', ha='center')
|
|
48
|
+
|
|
49
|
+
badge3 = patches.FancyBboxPatch((365, 45), 160, 65, boxstyle="round,pad=3",
|
|
50
|
+
facecolor="#1e293b", edgecolor="#f59e0b", linewidth=1.5)
|
|
51
|
+
ax.add_patch(badge3)
|
|
52
|
+
ax.text(445, 85, "< 1.0 GB", fontsize=16, fontweight='black', color='#f59e0b', ha='center')
|
|
53
|
+
ax.text(445, 60, "ACTIVE VRAM (RTX 3050)", fontsize=7.5, fontweight='bold', color='#94a3b8', ha='center')
|
|
54
|
+
|
|
55
|
+
plt.subplots_adjust(left=0, right=1, top=1, bottom=0)
|
|
56
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
57
|
+
plt.savefig(output_path, dpi=100)
|
|
58
|
+
plt.close()
|
|
59
|
+
print(f"Kaggle thumbnail generated at: {output_path} (Dimensions: 560x280)")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
out = Path("/home/deepak-r/Project/research/paper/figures/kaggle_thumbnail_560x280.png")
|
|
64
|
+
render_kaggle_thumbnail(out)
|