23f3003322 commited on
Commit
ec256ea
·
1 Parent(s): af43a76

processing round 2

Browse files
Files changed (6) hide show
  1. app/deployer.py +42 -0
  2. app/llm.py +133 -0
  3. app/main.py +16 -3
  4. app/round2fn.py +468 -0
  5. app/rounds.py +30 -5
  6. app/utils.py +1 -1
app/deployer.py CHANGED
@@ -211,6 +211,48 @@ async def enable_github_pages(repo: str):
211
  logger.error(f"Unexpected error enabling GitHub Pages: {str(e)}")
212
  raise
213
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
  async def notify_evaluation_url(evaluation_url: str, payload: dict):
216
  async with httpx.AsyncClient() as client:
 
211
  logger.error(f"Unexpected error enabling GitHub Pages: {str(e)}")
212
  raise
213
 
214
+ async def get_ref_sha( repo:str):
215
+ url = f"{GITHUB_API_URL}repos/{OWNER}/{repo}/git/ref/heads/main"
216
+ async with httpx.AsyncClient() as client:
217
+ response = await retry_request(client.get, url, headers=headers)
218
+ response.raise_for_status()
219
+ return response.json()["object"]["sha"]
220
+
221
+ async def get_blob_content( repo, sha):
222
+ url = f"{GITHUB_API_URL}repos/{OWNER}/{repo}/git/blobs/{sha}"
223
+ async with httpx.AsyncClient() as client:
224
+ response = await retry_request(client.get, url, headers=headers)
225
+ response.raise_for_status()
226
+ blob_data = response.json()
227
+ return base64.b64decode(blob_data["content"]).decode("utf-8")
228
+
229
+ async def get_files_from_github_repo(repo: str) -> List[FileContext]:
230
+ """
231
+ Fetches all files in the specified GitHub repo and branch using the GitHub API.
232
+ Returns a list of FileContext objects with filename and decoded content.
233
+ """
234
+
235
+ try:
236
+ commit_sha = await get_ref_sha( repo)
237
+ tree_sha = await get_tree_sha( repo, commit_sha)
238
+ # Fetch the tree with recursive=1
239
+ tree_url = f"{GITHUB_API_URL}repos/{OWNER}/{repo}/git/trees/{tree_sha}?recursive=1"
240
+ async with httpx.AsyncClient() as client:
241
+ response = await retry_request(client.get, tree_url, headers=headers)
242
+ response.raise_for_status()
243
+ tree_data = response.json()
244
+
245
+ files = []
246
+ for item in tree_data["tree"]:
247
+ if item["type"] == "blob":
248
+ content = await get_blob_content( repo, item["sha"])
249
+ files.append(FileContext(file_name=item["path"], file_content=content))
250
+ return files
251
+ except Exception as e:
252
+ logger.error(f"Error getting files from GitHub repo: {e}", exc_info=True)
253
+ raise
254
+
255
+
256
 
257
  async def notify_evaluation_url(evaluation_url: str, payload: dict):
258
  async with httpx.AsyncClient() as client:
app/llm.py CHANGED
@@ -36,6 +36,7 @@ Requirements:
36
  - If attachments are present, they should be used within the project logically matching the task description.
37
  - Provide all files necessary for deployment including at least an index.html.
38
  - Write a thorough README.md that includes:
 
39
  - Project summary
40
  - Setup instructions for GitHub Pages
41
  - Usage guide
@@ -121,3 +122,135 @@ Focus on quality, clarity, and correctness to deliver a ready-to-use GitHub Page
121
  logger.error(f"Error generating code with LLM: {e}", exc_info=True)
122
  # Raise runtime error to caller or optionally return empty list/fallback output
123
  raise RuntimeError(f"LLM code generation failed: {e}") from e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  - If attachments are present, they should be used within the project logically matching the task description.
37
  - Provide all files necessary for deployment including at least an index.html.
38
  - Write a thorough README.md that includes:
39
+ - the exact provided brief for the code generation with the heading 'main goal'
40
  - Project summary
41
  - Setup instructions for GitHub Pages
42
  - Usage guide
 
122
  logger.error(f"Error generating code with LLM: {e}", exc_info=True)
123
  # Raise runtime error to caller or optionally return empty list/fallback output
124
  raise RuntimeError(f"LLM code generation failed: {e}") from e
125
+
126
+
127
+ async def round2_code_modification_function(
128
+ files: List[FileContext],
129
+ task_object: TaskRequest
130
+ ) -> List[FileContext]:
131
+ """
132
+ Minimal Round 2 function - prevents loops by being ultra simple
133
+ """
134
+ print("Starting minimal Round 2 modification...")
135
+
136
+ try:
137
+ attachments_text = ""
138
+ if task_object.attachments and len(task_object.attachments) > 0:
139
+ attachments_text = "\nAttachments:\n" + "\n".join([f"- {att.name}: {att.url[:80]}..." for att in task_object.attachments])
140
+ else:
141
+ attachments_text = "\n(No attachments were provided with the request)"
142
+ # Create simple file info for the AI
143
+
144
+ files_str = "\n\n".join(
145
+ [f"--- START FILE: {f.file_name} ---\n{f.file_content}\n--- END FILE: {f.file_name} ---" for f in files])
146
+
147
+ # This is how you would create it in your Python function
148
+ # using f-strings.
149
+
150
+ prompt = f"""
151
+ **Objective:** Modify the following web project to satisfy the user's brief and pass all acceptance criteria.
152
+
153
+ ---
154
+
155
+ ### **User's Brief**
156
+
157
+ "{task_object.brief}"
158
+
159
+ ### **attachments given by user(if any)**
160
+
161
+ "{attachments_text}
162
+
163
+ ---
164
+
165
+ ### **Acceptance Criteria (Checks)**
166
+
167
+ The final code **MUST** pass all of the following checks. These are non-negotiable JavaScript expressions that will be evaluated in the browser's console. A failure to pass these checks means the task is a failure.
168
+
169
+ {task_object.checks}
170
+
171
+
172
+
173
+ ---
174
+
175
+ ### **Project Files**
176
+
177
+ Here are the complete contents of all files in the project. Analyze them and apply your changes where necessary.
178
+
179
+ {files_str}
180
+
181
+ ---
182
+
183
+ **Final Instruction:**
184
+ Perform the required modifications based on the brief and checks. Now, return the complete list of all project files in the required format.
185
+ """
186
+
187
+
188
+
189
+ simple_agent = Agent(
190
+ "openai:gpt-5-nano",
191
+ result_type=List[FileContext],
192
+ system_prompt=""" You are an expert AI software developer specializing in frontend web technologies (HTML, CSS, and JavaScript). Your primary mission is to intelligently modify an existing codebase to fulfill a user's request while adhering to a strict set of rules.
193
+
194
+ **Your Core Directives:**
195
+
196
+ 1. **Principle of Minimal Change:** You must operate on the principle of minimal intervention. Your goal is to be a precise surgical tool, not a wrecking ball. Only make the changes necessary to satisfy the user's brief. Do not refactor, rewrite, or alter code that is not directly related to the task.
197
+
198
+ 2. **Preserve File Integrity:** Do not add or delete files from the project unless the user's brief explicitly and unambiguously instructs you to do so. The structure of the project must be maintained.
199
+
200
+ 3. **Completeness is Mandatory:** Your final output MUST include the complete content of ALL original files provided to you, even the files you did not modify. This is non-negotiable and ensures the entire project context is returned.
201
+
202
+ 4. **Strict Adherence to Checks:** The user will provide a list of "checks" (JavaScript expressions). The modified code must ensure that every single one of these expressions evaluates to `true`. These checks are your primary definition of success.
203
+
204
+ 5. **Focus on Static Deployment:** Assume the final code needs to be immediately deployable to a static hosting service like GitHub Pages. Do not introduce any server-side logic, dependencies, or build steps unless specifically requested.
205
+
206
+ 6. **No Conversational Output:** Do not provide explanations, apologies, or any conversational text in your final output. Your response must strictly be the structured data containing the list of files and their content.
207
+ """
208
+
209
+ )
210
+
211
+ # Run with strict limits to prevent loops
212
+ result = await simple_agent.run(prompt)
213
+
214
+ # print(result)
215
+ return result.data
216
+
217
+ except Exception as e:
218
+ print(f"AI modification failed: {e}")
219
+ print("Using text-based fallback...")
220
+
221
+
222
+
223
+
224
+
225
+
226
+ prompt="""
227
+ Analyze the existing codebase and implement the following requirement with minimal changes:
228
+
229
+ Requirements:
230
+ 1. Make only targeted modifications to implement the new functionality
231
+ 2. Do not rewrite entire files - add incrementally to existing code
232
+ 3. Ensure all JavaScript validation checks pass
233
+ 4. Update the README to document the changes
234
+ 5. Maintain GitHub Pages compatibility
235
+ 6. Preserve all existing functionality
236
+
237
+ Please analyze the code, understand the requirements, and provide the modified files.
238
+ """
239
+
240
+
241
+ system_prompt="""You are an expert web developer tasked with making minimal, targeted modifications to an existing GitHub Pages codebase.
242
+
243
+ Your responsibilities:
244
+ 1. Analyze the existing code structure and functionality thoroughly
245
+ 2. Make ONLY the minimal changes needed to implement the new brief requirements
246
+ 3. Do NOT rewrite entire files or change the overall structure
247
+ 4. Ensure all modifications will pass the provided JavaScript validation checks
248
+ 5. Update the README file to reflect the changes made
249
+ 6. Preserve all existing functionality while adding new features
250
+
251
+ Guidelines:
252
+ - Add new elements, functions, or styles incrementally
253
+ - Modify existing code only when absolutely necessary
254
+ - Test your changes against validation checks mentally before finalizing
255
+ - Keep the same coding style and patterns as the original code
256
+ - Focus on GitHub Pages compatibility (static HTML, CSS, JS only)"""
app/main.py CHANGED
@@ -1,10 +1,23 @@
1
- from fastapi import FastAPI, HTTPException, status, Request,BackgroundTasks
2
  from fastapi.responses import JSONResponse
 
3
  from .models import TaskRequest
4
  from .utils import validate_secret
5
  from .rounds import round1,round2
6
- app = FastAPI()
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
  @app.post("/handle-task",status_code=status.HTTP_200_OK)
10
  async def handle_task(request: TaskRequest, background_tasks: BackgroundTasks):
@@ -27,7 +40,7 @@ async def handle_task(request: TaskRequest, background_tasks: BackgroundTasks):
27
  if request.round == 1 or request.round =="1":
28
  background_tasks.add_task(round1, request)
29
  elif request.round ==2 or request.round =="2":
30
- background_tasks.add_task(round2)
31
 
32
 
33
  return response
 
1
+ from fastapi import FastAPI, HTTPException, status,BackgroundTasks
2
  from fastapi.responses import JSONResponse
3
+ from fastapi.middleware.cors import CORSMiddleware
4
  from .models import TaskRequest
5
  from .utils import validate_secret
6
  from .rounds import round1,round2
 
7
 
8
+ app = FastAPI(
9
+ title="code genereation llm ",
10
+ description="code generation using llm",
11
+ version="1.0.0",
12
+ )
13
+
14
+ app.add_middleware(
15
+ CORSMiddleware,
16
+ allow_origins=["*"], # Allows all origins
17
+ allow_credentials=True,
18
+ allow_methods=["*"], # Allows all methods (GET, POST, etc.)
19
+ allow_headers=["*"], # Allows all headers
20
+ )
21
 
22
  @app.post("/handle-task",status_code=status.HTTP_200_OK)
23
  async def handle_task(request: TaskRequest, background_tasks: BackgroundTasks):
 
40
  if request.round == 1 or request.round =="1":
41
  background_tasks.add_task(round1, request)
42
  elif request.round ==2 or request.round =="2":
43
+ background_tasks.add_task(round2,request)
44
 
45
 
46
  return response
app/round2fn.py ADDED
@@ -0,0 +1,468 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # # Updated Round 2 Function with Correct Pydantic Models
2
+ # # This function works with the actual task format and FileContext models
3
+
4
+ # import json
5
+ # # import re
6
+ # from typing import Dict, List, Optional, Any
7
+ # from pydantic import BaseModel
8
+ # from pydantic_ai import Agent, RunContext
9
+ # from .models import FileContext,TaskRequest
10
+ # import logging
11
+
12
+ # import os
13
+ # from dotenv import load_dotenv
14
+ # load_dotenv()
15
+
16
+ # OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
17
+ # OPENAI_BASE_URL = os.getenv("OPENAI_BASE_URL")
18
+
19
+ # logger = logging.getLogger(__name__)
20
+ # logging.basicConfig(level=logging.INFO)
21
+
22
+
23
+ # # Pydantic models matching the provided format
24
+ # # class FileContext(BaseModel):
25
+ # # file_name: str
26
+ # # file_content: str
27
+
28
+ # class TaskObject(BaseModel):
29
+ # email: str
30
+ # secret: str
31
+ # task: str
32
+ # round: int
33
+ # nonce: str
34
+ # brief: str
35
+ # checks: List[Dict[str, str]]
36
+ # evaluation_url: str
37
+ # attachments: List[str]
38
+
39
+ # class ValidationCheck(BaseModel):
40
+ # js: str
41
+
42
+ # class CodeAnalysisContext(BaseModel):
43
+ # original_files: List[FileContext]
44
+ # task_brief: str
45
+ # validation_checks: List[ValidationCheck]
46
+ # attachments: List[str]
47
+
48
+ # class ModificationResult(BaseModel):
49
+ # """Pydantic model for the complete modification result"""
50
+ # modified_files: List[FileContext]
51
+ # validation_status: Dict[str, bool]
52
+ # summary: str
53
+
54
+ # def simulate_js_validation(html_content: str, js_content: str, check: ValidationCheck) -> bool:
55
+ # """
56
+ # Simulate JavaScript validation by analyzing code patterns
57
+ # This is a simplified version - in production you'd use a proper JS engine
58
+ # """
59
+ # combined_content = html_content + "\n" + js_content
60
+
61
+ # try:
62
+ # check_code = check.js
63
+
64
+ # # Check for element existence with tagName
65
+ # if "document.querySelector" in check_code and ".tagName" in check_code:
66
+ # selector_match = re.search(r'document\.querySelector\("([^"]+)"\)', check_code)
67
+ # tag_match = re.search(r'tagName === "([^"]+)"', check_code)
68
+
69
+ # if selector_match and tag_match:
70
+ # selector = selector_match.group(1)
71
+ # expected_tag = tag_match.group(1)
72
+
73
+ # # Check if HTML contains element with that ID and tag
74
+ # pattern = rf'<{expected_tag.lower()}[^>]*id=["\']?{re.escape(selector.replace("#", ""))}'
75
+ # return bool(re.search(pattern, combined_content, re.IGNORECASE))
76
+
77
+ # # Check for text content includes
78
+ # if ".textContent.includes" in check_code:
79
+ # selector_match = re.search(r'document\.querySelector\("([^"]+)"\)', check_code)
80
+ # text_match = re.search(r'textContent\.includes\("([^"]+)"\)', check_code)
81
+
82
+ # if selector_match and text_match:
83
+ # expected_text = text_match.group(1)
84
+ # return expected_text in combined_content
85
+
86
+ # # Check for script content includes
87
+ # if "script" in check_code.lower() and "textContent.includes" in check_code:
88
+ # url_match = re.search(r'textContent\.includes\("([^"]+)"\)', check_code)
89
+ # if url_match:
90
+ # expected_content = url_match.group(1)
91
+ # return expected_content in combined_content
92
+
93
+ # # Check for attributes (like aria-live)
94
+ # if ".getAttribute" in check_code:
95
+ # selector_match = re.search(r'document\.querySelector\("([^"]+)"\)', check_code)
96
+ # attr_match = re.search(r'getAttribute\("([^"]+)"\)', check_code)
97
+ # value_match = re.search(r'=== "([^"]+)"', check_code)
98
+
99
+ # if selector_match and attr_match and value_match:
100
+ # selector = selector_match.group(1).replace("#", "")
101
+ # attr_name = attr_match.group(1)
102
+ # expected_value = value_match.group(1)
103
+
104
+ # # Look for element with ID and attribute
105
+ # id_pattern = rf'id=["\']?{re.escape(selector)}["\']?'
106
+ # attr_pattern = rf'{re.escape(attr_name)}=["\']?{re.escape(expected_value)}["\']?'
107
+
108
+ # # Check if both ID and attribute exist in the content
109
+ # has_id = bool(re.search(id_pattern, combined_content, re.IGNORECASE))
110
+ # has_attr = bool(re.search(attr_pattern, combined_content, re.IGNORECASE))
111
+
112
+ # return has_id and has_attr
113
+
114
+ # # Check for double negation patterns (!!expression)
115
+ # if check_code.startswith("!!"):
116
+ # inner_check = check_code[2:] # Remove !!
117
+ # # Recursively check the inner expression
118
+ # inner_validation = ValidationCheck(js=inner_check)
119
+ # return simulate_js_validation(html_content, js_content, inner_validation)
120
+
121
+ # return False
122
+
123
+ # except Exception as e:
124
+ # print(f"Validation error: {e}")
125
+ # return False
126
+
127
+ # def analyze_existing_codebase(files: List[FileContext]) -> Dict[str, Any]:
128
+ # """Analyze the existing codebase to understand its structure and functionality"""
129
+ # analysis = {
130
+ # "html_files": [],
131
+ # "css_files": [],
132
+ # "js_files": [],
133
+ # "other_files": [],
134
+ # "existing_elements": [],
135
+ # "scripts_and_apis": []
136
+ # }
137
+
138
+ # for file in files:
139
+ # file_ext = file.file_name.split('.')[-1].lower()
140
+
141
+ # if file_ext == 'html':
142
+ # analysis["html_files"].append(file)
143
+ # # Extract form elements, IDs, classes
144
+ # ids = re.findall(r'id=["\']([^"\']+)["\']', file.file_content)
145
+ # analysis["existing_elements"].extend([f"#{id_val}" for id_val in ids])
146
+
147
+ # elif file_ext == 'css':
148
+ # analysis["css_files"].append(file)
149
+
150
+ # elif file_ext == 'js':
151
+ # analysis["js_files"].append(file)
152
+ # # Extract API calls and functions
153
+ # api_calls = re.findall(r'https://[^\s"\']+', file.file_content)
154
+ # analysis["scripts_and_apis"].extend(api_calls)
155
+
156
+ # else:
157
+ # analysis["other_files"].append(file)
158
+
159
+ # return analysis
160
+
161
+ # # Initialize Pydantic AI Agent
162
+ # code_modification_agent = Agent(
163
+ # "openai:gpt-5-nano",
164
+ # deps_type=CodeAnalysisContext,
165
+ # result_type=ModificationResult,
166
+ # system_prompt="""You are an expert web developer tasked with making minimal, targeted modifications to an existing GitHub Pages codebase.
167
+
168
+ # Your responsibilities:
169
+ # 1. Analyze the existing code structure and functionality thoroughly
170
+ # 2. Make ONLY the minimal changes needed to implement the new brief requirements
171
+ # 3. Do NOT rewrite entire files or change the overall structure
172
+ # 4. Ensure all modifications will pass the provided JavaScript validation checks
173
+ # 5. Update files to include new functionality while preserving existing features
174
+ # 6. Focus on GitHub Pages compatibility (static HTML, CSS, JS only)
175
+
176
+ # Guidelines:
177
+ # - Add new elements, functions, or styles incrementally
178
+ # - Modify existing code only when absolutely necessary
179
+ # - Test your changes against validation checks mentally before finalizing
180
+ # - Keep the same coding style and patterns as the original code
181
+ # - If checks require specific elements or attributes, ensure they are added
182
+ # - Pay special attention to accessibility attributes like aria-live when required"""
183
+ # )
184
+
185
+ # @code_modification_agent.tool
186
+ # async def analyze_codebase_structure(ctx: RunContext[CodeAnalysisContext]) -> str:
187
+ # """Analyze the structure and functionality of the existing codebase"""
188
+ # analysis = analyze_existing_codebase(ctx.deps.original_files)
189
+
190
+ # summary = []
191
+ # summary.append(f"Found {len(analysis['html_files'])} HTML files")
192
+ # summary.append(f"Found {len(analysis['css_files'])} CSS files")
193
+ # summary.append(f"Found {len(analysis['js_files'])} JavaScript files")
194
+ # summary.append(f"Existing elements: {', '.join(analysis['existing_elements'][:10])}")
195
+ # summary.append(f"API endpoints used: {', '.join(analysis['scripts_and_apis'][:3])}")
196
+
197
+ # return "\n".join(summary)
198
+
199
+ # @code_modification_agent.tool
200
+ # async def get_task_requirements(ctx: RunContext[CodeAnalysisContext]) -> str:
201
+ # """Get the new task requirements and brief"""
202
+ # brief = f"Task Brief: {ctx.deps.task_brief}"
203
+
204
+ # if ctx.deps.attachments:
205
+ # brief += f"\nAttachments: {', '.join(ctx.deps.attachments)}"
206
+
207
+ # brief += "\n\nValidation checks that MUST pass:"
208
+ # for i, check in enumerate(ctx.deps.validation_checks):
209
+ # brief += f"\n{i+1}. {check.js}"
210
+
211
+ # return brief
212
+
213
+ # @code_modification_agent.tool
214
+ # async def validate_against_checks(ctx: RunContext[CodeAnalysisContext], modified_files: List[FileContext]) -> Dict[str, bool]:
215
+ # """Validate modified files against the JavaScript validation checks"""
216
+ # results = {}
217
+
218
+ # # Combine all HTML and JS content for validation
219
+ # html_content = ""
220
+ # js_content = ""
221
+
222
+ # for file in modified_files:
223
+ # if file.file_name.endswith('.html'):
224
+ # html_content += file.file_content + "\n"
225
+ # elif file.file_name.endswith('.js'):
226
+ # js_content += file.file_content + "\n"
227
+
228
+ # for i, check in enumerate(ctx.deps.validation_checks):
229
+ # try:
230
+ # is_valid = simulate_js_validation(html_content, js_content, check)
231
+ # results[f"check_{i}"] = is_valid
232
+ # except Exception as e:
233
+ # results[f"check_{i}"] = False
234
+
235
+ # return results
236
+
237
+ # @code_modification_agent.tool
238
+ # async def suggest_file_modifications(ctx: RunContext[CodeAnalysisContext]) -> str:
239
+ # """Analyze what modifications are needed for each file based on the task brief and checks"""
240
+
241
+ # brief = ctx.deps.task_brief.lower()
242
+ # suggestions = []
243
+
244
+ # # Analyze what the checks require
245
+ # required_elements = set()
246
+ # required_attributes = {}
247
+ # required_content = []
248
+
249
+ # for check in ctx.deps.validation_checks:
250
+ # check_js = check.js
251
+
252
+ # # Extract required selectors
253
+ # selector_matches = re.findall(r'document\.querySelector\("([^"]+)"\)', check_js)
254
+ # for selector in selector_matches:
255
+ # required_elements.add(selector)
256
+
257
+ # # Extract required attributes
258
+ # if ".getAttribute" in check_js:
259
+ # attr_match = re.search(r'getAttribute\("([^"]+)"\).*?=== "([^"]+)"', check_js)
260
+ # if attr_match:
261
+ # attr_name, attr_value = attr_match.groups()
262
+ # selector_match = re.search(r'querySelector\("([^"]+)"\)', check_js)
263
+ # if selector_match:
264
+ # element_selector = selector_match.group(1)
265
+ # required_attributes[element_selector] = (attr_name, attr_value)
266
+
267
+ # # Extract required content
268
+ # if "textContent.includes" in check_js:
269
+ # content_match = re.search(r'textContent\.includes\("([^"]+)"\)', check_js)
270
+ # if content_match:
271
+ # required_content.append(content_match.group(1))
272
+
273
+ # suggestions.append(f"Brief requires: {brief}")
274
+ # suggestions.append(f"Required elements: {', '.join(required_elements)}")
275
+ # suggestions.append(f"Required attributes: {required_attributes}")
276
+ # suggestions.append(f"Required content: {', '.join(required_content)}")
277
+
278
+ # return "\n".join(suggestions)
279
+
280
+ # async def round2_code_modification_function(
281
+ # files: List[FileContext],
282
+ # task_object: Dict[str, Any]
283
+ # ) -> List[FileContext]:
284
+ # """
285
+ # Round 2 function that modifies existing GitHub repository files using Pydantic AI
286
+
287
+ # Args:
288
+ # files: List of FileContext objects from GitHub repository
289
+ # task_object: Dictionary containing brief, checks, attachments, etc.
290
+
291
+ # Returns:
292
+ # List[FileContext]: Modified files ready for GitHub Pages deployment
293
+ # """
294
+ # print("call is here")
295
+ # try:
296
+ # # Parse task object
297
+ # task = task_object
298
+
299
+ # # Convert checks to ValidationCheck objects
300
+ # validation_checks = [ValidationCheck(js=check['js']) for check in task.checks]
301
+
302
+ # # Create context for the AI agent
303
+ # context = CodeAnalysisContext(
304
+ # original_files=files,
305
+ # task_brief=task.brief,
306
+ # validation_checks=validation_checks,
307
+ # attachments=task.attachments
308
+ # )
309
+
310
+ # # Create the prompt for the AI agent
311
+ # prompt = f"""Analyze the existing codebase and implement the following requirement with minimal changes:
312
+
313
+ # BRIEF: {task.brief}
314
+
315
+ # VALIDATION CHECKS that must pass:
316
+ # {chr(10).join([f"- {check['js']}" for check in task.checks])}
317
+
318
+ # REQUIREMENTS:
319
+ # 1. Make only targeted modifications to implement the new functionality
320
+ # 2. Do not rewrite entire files - add incrementally to existing code
321
+ # 3. Ensure ALL JavaScript validation checks pass
322
+ # 4. Maintain GitHub Pages compatibility
323
+ # 5. Preserve all existing functionality
324
+ # 6. Add new elements/attributes/functionality as required by the checks
325
+
326
+ # Please analyze the code, understand the requirements, and provide the modified files that will pass all validation checks."""
327
+
328
+ # # Run the Pydantic AI agent
329
+ # result =await code_modification_agent.run(prompt, deps=context)
330
+ # print("Raw LLM output:", result.raw_output)
331
+ # print("Parsed data:", result.data)
332
+ # # Return the modified files in the required format
333
+ # return result.data.modified_files
334
+
335
+ # except Exception as e:
336
+ # # Fallback: return original files if modification fails
337
+ # print(f"Error in code modification: {str(e)}")
338
+ # # return files
339
+
340
+ # # Example usage matching the provided format
341
+ # if __name__ == "__main__":
342
+ # # Example files in FileContext format
343
+ # example_files = [
344
+ # FileContext(
345
+ # file_name="index.html",
346
+ # file_content='''<!DOCTYPE html>
347
+ # <html>
348
+ # <head>
349
+ # <title>GitHub User Info</title>
350
+ # <link rel="stylesheet" href="style.css">
351
+ # </head>
352
+ # <body>
353
+ # <form id="github-user-123">
354
+ # <input type="text" id="username" placeholder="Enter GitHub username">
355
+ # <button type="submit">Get User Info</button>
356
+ # </form>
357
+ # <div id="github-created-at"></div>
358
+ # <script src="script.js"></script>
359
+ # </body>
360
+ # </html>'''
361
+ # ),
362
+ # FileContext(
363
+ # file_name="script.js",
364
+ # file_content='''document.getElementById('github-user-123').addEventListener('submit', async function(e) {
365
+ # e.preventDefault();
366
+ # const username = document.getElementById('username').value;
367
+ # const response = await fetch(`https://api.github.com/users/${username}`);
368
+ # const user = await response.json();
369
+ # document.getElementById('github-created-at').textContent = user.created_at.split('T')[0];
370
+ # });'''
371
+ # ),
372
+ # FileContext(
373
+ # file_name="style.css",
374
+ # file_content='''body {
375
+ # font-family: Arial, sans-serif;
376
+ # margin: 20px;
377
+ # }
378
+
379
+ # form {
380
+ # margin-bottom: 20px;
381
+ # }
382
+
383
+ # input, button {
384
+ # padding: 10px;
385
+ # margin: 5px;
386
+ # }'''
387
+ # )
388
+ # ]
389
+
390
+ # # Example task object matching the provided format
391
+ # example_task = {
392
+ # "email": "student@example.com",
393
+ # "secret": "shamil",
394
+ # "task": "test-round2-1",
395
+ # "round": 2,
396
+ # "nonce": "ab12-...",
397
+ # "brief": "Display the account age in whole years inside #github-account-age alongside the creation date.",
398
+ # "checks": [
399
+ # {
400
+ # "js": "document.querySelector(\"#github-status\").getAttribute(\"aria-live\") === \"polite\""
401
+ # },
402
+ # {
403
+ # "js": "!!document.querySelector(\"script\").textContent.includes(\"github-status\")"
404
+ # }
405
+ # ],
406
+ # "evaluation_url": "http://0.0.0.0:8001/notify",
407
+ # "attachments": []
408
+ # }
409
+
410
+ # # Run the function
411
+ # modified_files = round2_code_modification_function(
412
+ # files=example_files,
413
+ # task_object=example_task
414
+ # )
415
+
416
+ # print("Modified Files:")
417
+ # for file in modified_files:
418
+ # print(f"\n--- {file.file_name} ---")
419
+ # print(file.file_content[:300] + "..." if len(file.file_content) > 300 else file.file_content)
420
+
421
+
422
+
423
+
424
+
425
+ # This version removes most complexity to prevent loops
426
+
427
+ from typing import Dict, List, Any
428
+ from pydantic import BaseModel
429
+ from pydantic_ai import Agent
430
+ from .models import FileContext
431
+ import json
432
+
433
+ # Minimal agent setup
434
+
435
+
436
+
437
+
438
+
439
+
440
+
441
+
442
+
443
+ # prompt = f"""Analyze the existing codebase and implement the following requirement with minimal changes:
444
+
445
+ # FILES TO MODIFY: {json.dumps(files_info, indent=2)}
446
+
447
+ # BRIEF: {brief}
448
+
449
+ # attachments (if any): {attachments_text}
450
+
451
+ # CHECKS (for reference): {checks}
452
+
453
+ # REQUIREMENTS:
454
+ # 1. Make only targeted modifications to implement the new functionality
455
+ # 2. Do not rewrite entire files - add incrementally to existing code
456
+ # 3. Ensure ALL JavaScript validation checks pass
457
+ # 4. Maintain GitHub Pages compatibility
458
+ # 5. Preserve all existing functionality
459
+ # 6. update/add elements/attributes/functionality as required by the checks
460
+ # 7. update the readme file with the changes made
461
+ # 8. Do not include text explanations in the output; only return the code files and README as specified
462
+ # 9. code should be ready to deploy in Github pages
463
+ # 10. Output format:
464
+ # Return only a JSON array of objects where each object has:
465
+ # - "file_name": string
466
+ # - "file_content": string
467
+
468
+ # Please analyze the code, understand the requirements, and provide the modified files that will pass all validation checks."""
app/rounds.py CHANGED
@@ -1,9 +1,34 @@
1
  from .models import TaskRequest
2
- from .deployer import create_github_repo,notify_evaluation_url,push_files_to_github_repo,enable_github_pages
3
- from .llm import genereate_code_with_llm
4
 
5
- def round2():
6
- print("inside round 2")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
 
9
  async def round1(request: TaskRequest):
@@ -31,4 +56,4 @@ async def round1(request: TaskRequest):
31
  }
32
  await notify_evaluation_url(request.evaluation_url, payload)
33
  except Exception as e:
34
- print(f"Error in background task: {e}")
 
1
  from .models import TaskRequest
2
+ from .deployer import create_github_repo,notify_evaluation_url,push_files_to_github_repo,enable_github_pages,get_files_from_github_repo
3
+ from .llm import genereate_code_with_llm, round2_code_modification_function
4
 
5
+ async def round2(request: TaskRequest):
6
+ try:
7
+ updated_files = await get_files_from_github_repo(repo=request.task)
8
+ # print (updated_files)
9
+
10
+ updated_files = await round2_code_modification_function(files=updated_files,task_object=request)
11
+
12
+ # print( updated_files)
13
+ commit_sha = await push_files_to_github_repo(repo=request.task,files=updated_files)
14
+
15
+ pages_reponse = await enable_github_pages(repo=request.task)
16
+
17
+ pages_url = pages_reponse.get("pages_url")
18
+ repo_url = pages_reponse.get("repo_url")
19
+
20
+ payload = {
21
+ "email": request.email,
22
+ "task": request.task,
23
+ "round": request.round,
24
+ "nonce": request.nonce,
25
+ "repo_url": repo_url,
26
+ "commit_sha": commit_sha,
27
+ "pages_url": pages_url,
28
+ }
29
+ await notify_evaluation_url(request.evaluation_url, payload)
30
+ except Exception as e:
31
+ print(f"Error in background task round 2: {e}")
32
 
33
 
34
  async def round1(request: TaskRequest):
 
56
  }
57
  await notify_evaluation_url(request.evaluation_url, payload)
58
  except Exception as e:
59
+ print(f"Error in background task round 1: {e}")
app/utils.py CHANGED
@@ -2,7 +2,7 @@ import os
2
  import httpx
3
  import logging
4
  import asyncio
5
- API_SECRET = os.getenv("API_SECRET", "shamil")
6
 
7
 
8
  logger = logging.getLogger(__name__)
 
2
  import httpx
3
  import logging
4
  import asyncio
5
+ API_SECRET = os.getenv("API_SECRET",)
6
 
7
 
8
  logger = logging.getLogger(__name__)