terryyz commited on
Commit
1bb2113
·
1 Parent(s): 80f59bb
.gitignore CHANGED
@@ -26,7 +26,7 @@ share/python-wheels/
26
  *.egg
27
  MANIFEST
28
  run.sh
29
-
30
  # PyInstaller
31
  # Usually these files are written by a python script from a template
32
  # before PyInstaller builds the exe, so as to inject date/other infos into it.
 
26
  *.egg
27
  MANIFEST
28
  run.sh
29
+ logs/
30
  # PyInstaller
31
  # Usually these files are written by a python script from a template
32
  # before PyInstaller builds the exe, so as to inject date/other infos into it.
app.py CHANGED
The diff for this file is too large to render. See raw diff
 
completion.py CHANGED
@@ -60,7 +60,6 @@ def load_model_answers(answer_dir: str):
60
  if not os.path.isdir(os.path.join(answer_dir, folder)):
61
  continue
62
  if not os.path.exists(os.path.join(answer_dir, folder, "generation.jsonl")):
63
- print(f"WARNING: {folder} does not have generation.jsonl, skip it.")
64
  continue
65
  filenames.append(os.path.join(answer_dir, folder, "generation.jsonl"))
66
 
@@ -111,7 +110,6 @@ def load_model_answers_and_execution_results(data_dir: str):
111
  if not os.path.isdir(os.path.join(data_dir, folder)):
112
  continue
113
  if not os.path.exists(os.path.join(data_dir, folder, "execution_results.jsonl")):
114
- print(f"WARNING: {folder} does not have execution_results.jsonl, skip it.")
115
  continue
116
  filenames.append(os.path.join(data_dir, folder, "execution_results.jsonl"))
117
 
@@ -205,41 +203,10 @@ def chat_completion_openai(model, messages, temperature, max_tokens, api_dict=No
205
  }
206
  break
207
  except openai.RateLimitError as e:
208
- print(type(e), e)
209
  time.sleep(API_RETRY_SLEEP)
210
  except openai.BadRequestError as e:
211
- print("=== DEBUG: OpenAI BadRequestError ===")
212
- print("Error type:", type(e))
213
- print("Error message:", str(e))
214
- print("=== Analyzing messages for image issues ===")
215
- for i, msg in enumerate(messages):
216
- print(f"Message {i} role: {msg.get('role', 'unknown')}")
217
- if "content" in msg:
218
- content = msg["content"]
219
- if isinstance(content, list):
220
- for j, item in enumerate(content):
221
- if isinstance(item, dict) and item.get("type") == "image_url":
222
- url = item.get("image_url", {}).get("url", "")
223
- if url.startswith("data:image/png;base64,"):
224
- base64_part = url[22:] # Remove "data:image/png;base64," prefix
225
- print(f" Image {j}: base64 length = {len(base64_part)}")
226
- if len(base64_part) < 50:
227
- print(f" *** ISSUE: Image {j} has very short/empty base64: '{url}'")
228
- elif url.startswith("data:image/"):
229
- print(f" Image {j}: Non-PNG data URL: {url[:50]}...")
230
- else:
231
- print(f" Image {j}: Unexpected URL format: {url[:50]}...")
232
- elif isinstance(item, dict) and item.get("type") == "text":
233
- text_content = item.get("text", "")
234
- print(f" Text {j}: {len(text_content)} chars")
235
- else:
236
- print(f" Content {j}: {type(item)} - {str(item)[:50]}...")
237
- else:
238
- print(f" Content: {type(content)} - {str(content)[:100]}...")
239
- print("=== End debug info ===")
240
  break
241
  except KeyError:
242
- print(type(e), e)
243
  break
244
 
245
  return output
@@ -304,41 +271,10 @@ def chat_completion_openai_thinking(model, messages, api_dict=None, **kwargs):
304
  }
305
  break
306
  except openai.RateLimitError as e:
307
- print(type(e), e)
308
  time.sleep(API_RETRY_SLEEP)
309
  except openai.BadRequestError as e:
310
- print("=== DEBUG: OpenAI BadRequestError ===")
311
- print("Error type:", type(e))
312
- print("Error message:", str(e))
313
- print("=== Analyzing messages for image issues ===")
314
- for i, msg in enumerate(messages):
315
- print(f"Message {i} role: {msg.get('role', 'unknown')}")
316
- if "content" in msg:
317
- content = msg["content"]
318
- if isinstance(content, list):
319
- for j, item in enumerate(content):
320
- if isinstance(item, dict) and item.get("type") == "image_url":
321
- url = item.get("image_url", {}).get("url", "")
322
- if url.startswith("data:image/png;base64,"):
323
- base64_part = url[22:] # Remove "data:image/png;base64," prefix
324
- print(f" Image {j}: base64 length = {len(base64_part)}")
325
- if len(base64_part) < 50:
326
- print(f" *** ISSUE: Image {j} has very short/empty base64: '{url}'")
327
- elif url.startswith("data:image/"):
328
- print(f" Image {j}: Non-PNG data URL: {url[:50]}...")
329
- else:
330
- print(f" Image {j}: Unexpected URL format: {url[:50]}...")
331
- elif isinstance(item, dict) and item.get("type") == "text":
332
- text_content = item.get("text", "")
333
- print(f" Text {j}: {len(text_content)} chars")
334
- else:
335
- print(f" Content {j}: {type(item)} - {str(item)[:50]}...")
336
- else:
337
- print(f" Content: {type(content)} - {str(content)[:100]}...")
338
- print("=== End debug info ===")
339
  break
340
  except KeyError:
341
- print(type(e), e)
342
  break
343
 
344
  return output
@@ -382,7 +318,6 @@ def chat_completion_deepseek_reasoner(messages, api_dict, **kwargs):
382
  }
383
  break
384
  except Exception as e:
385
- print(type(e), e)
386
  time.sleep(API_RETRY_SLEEP)
387
 
388
  return output
@@ -426,7 +361,6 @@ def chat_completion_deepseek(messages, max_tokens, api_dict, **kwargs):
426
  }
427
  break
428
  except Exception as e:
429
- print(type(e), e)
430
  time.sleep(API_RETRY_SLEEP)
431
 
432
  return output
@@ -463,7 +397,6 @@ def chat_completion_anthropic(model, messages, temperature, max_tokens, api_dict
463
  }
464
  break
465
  except anthropic.APIError as e:
466
- print(type(e), e)
467
  time.sleep(API_RETRY_SLEEP)
468
  return output
469
 
@@ -494,7 +427,6 @@ def chat_completion_anthropic_thinking(model, messages, max_tokens, budget_token
494
  }
495
  break
496
  except anthropic.APIError as e:
497
- print(type(e), e)
498
  time.sleep(API_RETRY_SLEEP)
499
 
500
  return output
@@ -525,7 +457,6 @@ def chat_completion_mistral(model, messages, temperature, max_tokens, **kwargs):
525
  }
526
  break
527
  except MistralException as e:
528
- print(type(e), e)
529
  break
530
 
531
  return output
@@ -558,7 +489,6 @@ def chat_completion_xai(model, messages, temperature, max_tokens, api_dict=None,
558
  }
559
  break
560
  except Exception as e:
561
- print(type(e), e)
562
  time.sleep(API_RETRY_SLEEP)
563
 
564
  return output
@@ -582,7 +512,6 @@ def chat_completion_litellm(model, messages, temperature, max_tokens, api_dict=N
582
  }
583
  break
584
  except Exception as e:
585
- print(type(e), e)
586
  time.sleep(API_RETRY_SLEEP)
587
 
588
  return output
@@ -729,7 +658,6 @@ def http_completion_gemini(model, messages, **kwargs):
729
  "answer": response.json()["candidates"][0]["content"]["parts"][0]["text"],
730
  }
731
  except KeyError as e:
732
- print(type(e), e)
733
  print(response.json())
734
  return output
735
 
@@ -839,10 +767,8 @@ def chat_completion_cohere(model, messages, temperature, max_tokens, **kwargs):
839
  }
840
  break
841
  except cohere.core.api_error.ApiError as e:
842
- print(type(e), e)
843
  raise
844
  except Exception as e:
845
- print(type(e), e)
846
  break
847
 
848
  return output
@@ -1156,7 +1082,6 @@ def chat_completion_aws_bedrock_claude(messages, api_dict=None, aws_region="us-w
1156
  break
1157
 
1158
  except Exception as e:
1159
- print(type(e), e)
1160
  time.sleep(API_RETRY_SLEEP)
1161
 
1162
  return output
@@ -1230,7 +1155,6 @@ def chat_completion_aws_bedrock_mistral(messages, api_dict=None, aws_region="us-
1230
  break
1231
 
1232
  except Exception as e:
1233
- print(type(e), e)
1234
  time.sleep(API_RETRY_SLEEP)
1235
 
1236
  return output
 
60
  if not os.path.isdir(os.path.join(answer_dir, folder)):
61
  continue
62
  if not os.path.exists(os.path.join(answer_dir, folder, "generation.jsonl")):
 
63
  continue
64
  filenames.append(os.path.join(answer_dir, folder, "generation.jsonl"))
65
 
 
110
  if not os.path.isdir(os.path.join(data_dir, folder)):
111
  continue
112
  if not os.path.exists(os.path.join(data_dir, folder, "execution_results.jsonl")):
 
113
  continue
114
  filenames.append(os.path.join(data_dir, folder, "execution_results.jsonl"))
115
 
 
203
  }
204
  break
205
  except openai.RateLimitError as e:
 
206
  time.sleep(API_RETRY_SLEEP)
207
  except openai.BadRequestError as e:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  break
209
  except KeyError:
 
210
  break
211
 
212
  return output
 
271
  }
272
  break
273
  except openai.RateLimitError as e:
 
274
  time.sleep(API_RETRY_SLEEP)
275
  except openai.BadRequestError as e:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
276
  break
277
  except KeyError:
 
278
  break
279
 
280
  return output
 
318
  }
319
  break
320
  except Exception as e:
 
321
  time.sleep(API_RETRY_SLEEP)
322
 
323
  return output
 
361
  }
362
  break
363
  except Exception as e:
 
364
  time.sleep(API_RETRY_SLEEP)
365
 
366
  return output
 
397
  }
398
  break
399
  except anthropic.APIError as e:
 
400
  time.sleep(API_RETRY_SLEEP)
401
  return output
402
 
 
427
  }
428
  break
429
  except anthropic.APIError as e:
 
430
  time.sleep(API_RETRY_SLEEP)
431
 
432
  return output
 
457
  }
458
  break
459
  except MistralException as e:
 
460
  break
461
 
462
  return output
 
489
  }
490
  break
491
  except Exception as e:
 
492
  time.sleep(API_RETRY_SLEEP)
493
 
494
  return output
 
512
  }
513
  break
514
  except Exception as e:
 
515
  time.sleep(API_RETRY_SLEEP)
516
 
517
  return output
 
658
  "answer": response.json()["candidates"][0]["content"]["parts"][0]["text"],
659
  }
660
  except KeyError as e:
 
661
  print(response.json())
662
  return output
663
 
 
767
  }
768
  break
769
  except cohere.core.api_error.ApiError as e:
 
770
  raise
771
  except Exception as e:
 
772
  break
773
 
774
  return output
 
1082
  break
1083
 
1084
  except Exception as e:
 
1085
  time.sleep(API_RETRY_SLEEP)
1086
 
1087
  return output
 
1155
  break
1156
 
1157
  except Exception as e:
 
1158
  time.sleep(API_RETRY_SLEEP)
1159
 
1160
  return output
conversation.py CHANGED
@@ -2314,41 +2314,30 @@ register_conv_template(
2314
  if __name__ == "__main__":
2315
  from fastchat.conversation import get_conv_template
2316
 
2317
- print("-- Vicuna template --")
2318
  conv = get_conv_template("vicuna_v1.1")
2319
  conv.append_message(conv.roles[0], "Hello!")
2320
  conv.append_message(conv.roles[1], "Hi!")
2321
  conv.append_message(conv.roles[0], "How are you?")
2322
  conv.append_message(conv.roles[1], None)
2323
- print(conv.get_prompt())
2324
 
2325
- print("\n")
2326
 
2327
- print("-- Llama-2 template --")
2328
  conv = get_conv_template("llama-2")
2329
  conv.set_system_message("You are a helpful, respectful and honest assistant.")
2330
  conv.append_message(conv.roles[0], "Hello!")
2331
  conv.append_message(conv.roles[1], "Hi!")
2332
  conv.append_message(conv.roles[0], "How are you?")
2333
  conv.append_message(conv.roles[1], None)
2334
- print(conv.get_prompt())
2335
 
2336
- print("\n")
2337
 
2338
- print("-- ChatGPT template --")
2339
  conv = get_conv_template("chatgpt")
2340
  conv.append_message(conv.roles[0], "Hello!")
2341
  conv.append_message(conv.roles[1], "Hi!")
2342
  conv.append_message(conv.roles[0], "How are you?")
2343
  conv.append_message(conv.roles[1], None)
2344
- print(conv.to_openai_api_messages())
2345
 
2346
- print("\n")
2347
 
2348
- print("-- Claude template --")
2349
  conv = get_conv_template("claude")
2350
  conv.append_message(conv.roles[0], "Hello!")
2351
  conv.append_message(conv.roles[1], "Hi!")
2352
  conv.append_message(conv.roles[0], "How are you?")
2353
  conv.append_message(conv.roles[1], None)
2354
- print(conv.get_prompt())
 
2314
  if __name__ == "__main__":
2315
  from fastchat.conversation import get_conv_template
2316
 
 
2317
  conv = get_conv_template("vicuna_v1.1")
2318
  conv.append_message(conv.roles[0], "Hello!")
2319
  conv.append_message(conv.roles[1], "Hi!")
2320
  conv.append_message(conv.roles[0], "How are you?")
2321
  conv.append_message(conv.roles[1], None)
 
2322
 
 
2323
 
 
2324
  conv = get_conv_template("llama-2")
2325
  conv.set_system_message("You are a helpful, respectful and honest assistant.")
2326
  conv.append_message(conv.roles[0], "Hello!")
2327
  conv.append_message(conv.roles[1], "Hi!")
2328
  conv.append_message(conv.roles[0], "How are you?")
2329
  conv.append_message(conv.roles[1], None)
 
2330
 
 
2331
 
 
2332
  conv = get_conv_template("chatgpt")
2333
  conv.append_message(conv.roles[0], "Hello!")
2334
  conv.append_message(conv.roles[1], "Hi!")
2335
  conv.append_message(conv.roles[0], "How are you?")
2336
  conv.append_message(conv.roles[1], None)
 
2337
 
 
2338
 
 
2339
  conv = get_conv_template("claude")
2340
  conv.append_message(conv.roles[0], "Hello!")
2341
  conv.append_message(conv.roles[1], "Hi!")
2342
  conv.append_message(conv.roles[0], "How are you?")
2343
  conv.append_message(conv.roles[1], None)
 
requirements.txt CHANGED
@@ -21,4 +21,6 @@ tree-sitter-php
21
  tree-sitter-typescript
22
  tree-sitter-c
23
  e2b-code-interpreter==1.5.2
24
- azure-storage-blob
 
 
 
21
  tree-sitter-typescript
22
  tree-sitter-c
23
  e2b-code-interpreter==1.5.2
24
+ azure-storage-blob
25
+ huggingface_hub
26
+ datasets
sandbox/code_analyzer.py CHANGED
@@ -84,7 +84,7 @@ def extract_python_imports(code: str) -> list[str]:
84
  if len(node.args) > 0 and isinstance(node.args[0], ast.Str):
85
  packages.add(node.args[0].s.split('.')[0])
86
  except Exception as e:
87
- print(f"Error processing node {type(node)}: {e}")
88
  continue
89
 
90
  # Filter out standard library modules using sys.stdlib_module_names
@@ -114,11 +114,11 @@ def extract_js_imports(code: str) -> list[str]:
114
  try:
115
  tree = ts_parser.parse(code_bytes)
116
  except Exception as e:
117
- print(f"TypeScript parsing failed: {e}")
118
  try:
119
  tree = js_parser.parse(code_bytes)
120
  except Exception as e:
121
- print(f"JavaScript parsing failed: {e}")
122
  tree = None
123
 
124
  if tree is None:
@@ -206,7 +206,7 @@ def extract_js_imports(code: str) -> list[str]:
206
  return list(packages)
207
 
208
  except Exception as e:
209
- print(f"Tree-sitter parsing failed: {e}")
210
  # Fallback to basic regex parsing if tree-sitter fails
211
  packages: Set[str] = set()
212
 
@@ -240,9 +240,9 @@ def extract_js_imports(code: str) -> list[str]:
240
  return list(packages)
241
 
242
 
243
- def determine_python_environment(code: str, imports: list[str]) -> SandboxEnvironment | None:
244
  '''
245
- Determine Python sandbox environment based on imports and AST analysis.
246
  '''
247
  try:
248
  tree = ast.parse(code)
@@ -255,34 +255,34 @@ def determine_python_environment(code: str, imports: list[str]) -> SandboxEnviro
255
  except SyntaxError:
256
  pass
257
 
258
- # Check imports for framework detection
259
- if 'pygame' in imports:
260
  return SandboxEnvironment.PYGAME
261
- elif 'gradio' in imports:
262
  return SandboxEnvironment.GRADIO
263
- elif 'streamlit' in imports:
264
  return SandboxEnvironment.STREAMLIT
265
- # elif 'nicegui' in imports:
266
  # return SandboxEnvironment.NICEGUI
267
 
268
  return SandboxEnvironment.PYTHON_RUNNER
269
 
270
 
271
- def determine_jsts_environment(code: str, imports: list[str]) -> SandboxEnvironment | None:
272
  '''
273
- Determine JavaScript/TypeScript sandbox environment based on imports and AST analysis.
274
  '''
275
  # First check for Vue SFC structure
276
  if '<template>' in code or '<script setup' in code:
277
  return SandboxEnvironment.VUE
278
 
279
- # Check imports for framework detection
280
- react_packages = {'react', '@react', 'next', '@next'}
281
  vue_packages = {'vue', '@vue', 'nuxt', '@nuxt'}
282
 
283
- if any(pkg in react_packages for pkg in imports):
284
  return SandboxEnvironment.REACT
285
- elif any(pkg in vue_packages for pkg in imports):
286
  return SandboxEnvironment.VUE
287
 
288
  try:
@@ -345,7 +345,7 @@ def determine_jsts_environment(code: str, imports: list[str]) -> SandboxEnvironm
345
  return SandboxEnvironment.VUE
346
 
347
  except Exception as e:
348
- print(f"Tree-sitter parsing error: {e}")
349
 
350
  return SandboxEnvironment.JAVASCRIPT_RUNNER
351
 
@@ -434,7 +434,7 @@ def detect_js_ts_code_lang(code: str) -> str:
434
  return 'typescript'
435
 
436
  except Exception as e:
437
- print(f"Tree-sitter parsing error: {e}")
438
  # Fallback to basic checks if parsing fails
439
  pass
440
 
@@ -569,17 +569,17 @@ def extract_js_from_html_script_tags(code: str) -> list[str]:
569
  return list(packages)
570
 
571
 
572
- def extract_code_from_markdown(message: str, enable_auto_env: bool = False) -> tuple[str, str, tuple[list[str], list[str]], SandboxEnvironment | None] | None:
573
  '''
574
  Extracts code from a markdown message by parsing code blocks directly.
575
  Determines sandbox environment based on code content and frameworks used.
576
 
577
  Returns:
578
- tuple[str, str, tuple[list[str], list[str]], SandboxEnvironment | None]: A tuple:
579
  1. code - the longest code block found
580
  2. code language
581
- 3. sandbox python and npm dependencies (extracted using static analysis)
582
- 4. sandbox environment determined from code content
583
  '''
584
  code_block_regex = r'```(?P<code_lang>[\w\+\#\-\.]*)?[ \t]*\r?\n?(?P<code>.*?)```'
585
  matches = list(re.finditer(code_block_regex, message, re.DOTALL))
@@ -591,9 +591,19 @@ def extract_code_from_markdown(message: str, enable_auto_env: bool = False) -> t
591
  low_priority_languages = ['bash', 'shell',
592
  'sh', 'zsh', 'powershell', 'pwsh', '']
593
 
 
 
 
 
 
 
 
 
 
 
594
  # Find the main code block by avoiding low-priority languages
595
- main_code = None
596
- main_code_lang = None
597
  max_length = 0
598
 
599
  for match in matches:
@@ -604,11 +614,6 @@ def extract_code_from_markdown(message: str, enable_auto_env: bool = False) -> t
604
  main_code_lang = code_lang
605
  max_length = len(code)
606
 
607
- # Fallback to the longest code block if no main code was found
608
- if not main_code:
609
- longest_match = max(matches, key=lambda m: len(m.group('code')))
610
- main_code = longest_match.group('code').strip()
611
- main_code_lang = (longest_match.group('code_lang') or '').lower()
612
 
613
  # Define language prefixes for each environment
614
  python_prefixes = ['py', 'ipython', 'pygame', 'gradio', 'streamlit']
@@ -625,45 +630,31 @@ def extract_code_from_markdown(message: str, enable_auto_env: bool = False) -> t
625
  rust_prefixes = ['rust']
626
  csharp_prefixes = ['cs', 'csharp', 'dotnet']
627
 
628
- # Extract package dependencies from the main program
629
- python_packages: list[str] = []
630
- npm_packages: list[str] = []
631
-
632
  # Helper function to check if any prefix matches
633
  def matches_prefix(lang: str, prefixes: list[str]) -> bool:
634
  return any(lang.lower().startswith(prefix) for prefix in prefixes)
635
 
 
636
  if matches_prefix(main_code_lang, python_prefixes):
637
- python_packages = extract_python_imports(main_code)
638
- extra_python_packages, main_code = extract_inline_pip_install_commands(
639
- main_code)
640
- python_packages.extend(extra_python_packages)
641
- sandbox_env_name = determine_python_environment(
642
- main_code, python_packages)
643
  elif matches_prefix(main_code_lang, vue_prefixes):
644
- npm_packages = extract_js_imports(main_code)
645
  sandbox_env_name = SandboxEnvironment.VUE
646
  main_code_lang = detect_js_ts_code_lang(main_code)
647
  elif matches_prefix(main_code_lang, react_prefixes):
648
- npm_packages = extract_js_imports(main_code)
649
  sandbox_env_name = SandboxEnvironment.REACT
650
  main_code_lang = detect_js_ts_code_lang(main_code)
651
  elif ('<!DOCTYPE html>' in main_code and ('<head' in main_code or '<body' in main_code)) or (main_code.strip().startswith('<svg')) or (not matches_prefix(main_code_lang, [*react_prefixes, *vue_prefixes, *js_prefixes, *ts_prefixes]) and ('<html' in main_code or '<!DOCTYPE html>' in main_code)):
652
- npm_packages = extract_js_from_html_script_tags(main_code)
653
  sandbox_env_name = SandboxEnvironment.HTML
654
  main_code_lang = 'html'
655
  elif matches_prefix(main_code_lang, js_prefixes):
656
  main_code_lang = 'javascript'
657
- npm_packages = extract_js_imports(main_code)
658
- sandbox_env_name = determine_jsts_environment(main_code, npm_packages)
659
  elif matches_prefix(main_code_lang, ts_prefixes):
660
  main_code_lang = 'typescript'
661
- npm_packages = extract_js_imports(main_code)
662
- sandbox_env_name = determine_jsts_environment(main_code, npm_packages)
663
  elif matches_prefix(main_code_lang, html_prefixes):
664
  main_code_lang = detect_js_ts_code_lang(main_code)
665
- npm_packages = extract_js_imports(main_code)
666
- sandbox_env_name = determine_jsts_environment(main_code, npm_packages)
667
  elif matches_prefix(main_code_lang, mermaid_prefixes):
668
  main_code_lang = 'markdown'
669
  sandbox_env_name = SandboxEnvironment.MERMAID
@@ -681,25 +672,14 @@ def extract_code_from_markdown(message: str, enable_auto_env: bool = False) -> t
681
  sandbox_env_name = SandboxEnvironment.RUST_RUNNER
682
  elif main_code_lang == 'c':
683
  main_code_lang = 'c'
684
- sandbox_env_name = sandbox_env_name = SandboxEnvironment.C_RUNNER
685
  else:
686
  sandbox_env_name = None
687
 
688
- all_python_packages: Set[str] = set(python_packages)
689
- all_npm_packages: Set[str] = set(npm_packages)
690
-
691
- for match in matches:
692
- code = match.group('code').strip()
693
- if code != main_code:
694
- install_python_packages, install_npm_packages = extract_installation_commands(
695
- code)
696
- all_python_packages.update(install_python_packages)
697
- all_npm_packages.update(install_npm_packages)
698
-
699
  if not main_code_lang:
700
  main_code_lang = 'markdown'
701
 
702
- return main_code, main_code_lang, (list(all_python_packages), list(all_npm_packages)), sandbox_env_name
703
 
704
 
705
  def create_placeholder_svg_data_url(width: int, height: int) -> str:
@@ -735,7 +715,7 @@ def create_placeholder_svg_data_url(width: int, height: int) -> str:
735
  encoded_svg = base64.b64encode(svg.encode('utf-8')).decode('utf-8')
736
  return f'data:image/svg+xml;base64,{encoded_svg}'
737
  except Exception as e:
738
- print(f'Error encoding SVG: {e}')
739
  # Fallback to a simple colored div
740
  return f'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0ie3dpZHRofSIgaGVpZ2h0PSJ7aGVpZ2h0fSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZjNmNGY2Ii8+PC9zdmc+'
741
 
@@ -760,17 +740,17 @@ def replace_placeholder_urls(code: str) -> str:
760
 
761
  # Validate dimensions
762
  if width <= 0 or height <= 0:
763
- print(f'Warning: Invalid dimensions {width}x{height}, using default 100x100')
764
  width, height = 100, 100
765
  elif width > 10000 or height > 10000:
766
- print(f'Warning: Dimensions {width}x{height} are very large, capping at 1000x1000')
767
  width, height = min(width, 1000), min(height, 1000)
768
 
769
- print(f'Replacing placeholder URL with SVG: {width}x{height}')
770
  data_url = create_placeholder_svg_data_url(width, height)
771
  return data_url
772
  except Exception as e:
773
- print(f'Error replacing placeholder URL: {e}')
774
  # Return a simple fallback
775
  return 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZjNmNGY2Ii8+PC9zdmc+'
776
 
@@ -780,10 +760,10 @@ def replace_placeholder_urls(code: str) -> str:
780
  try:
781
  # Replace all occurrences
782
  result = re.sub(pattern, replacer, code)
783
- print(f'Placeholder URL replacement completed successfully')
784
  return result
785
  except Exception as e:
786
- print(f'Error during placeholder URL replacement: {e}')
787
  return code # Return original code if replacement fails
788
 
789
 
 
84
  if len(node.args) > 0 and isinstance(node.args[0], ast.Str):
85
  packages.add(node.args[0].s.split('.')[0])
86
  except Exception as e:
87
+ pass
88
  continue
89
 
90
  # Filter out standard library modules using sys.stdlib_module_names
 
114
  try:
115
  tree = ts_parser.parse(code_bytes)
116
  except Exception as e:
117
+ pass
118
  try:
119
  tree = js_parser.parse(code_bytes)
120
  except Exception as e:
121
+ pass
122
  tree = None
123
 
124
  if tree is None:
 
206
  return list(packages)
207
 
208
  except Exception as e:
209
+ pass
210
  # Fallback to basic regex parsing if tree-sitter fails
211
  packages: Set[str] = set()
212
 
 
240
  return list(packages)
241
 
242
 
243
+ def determine_python_environment(code: str, install_command: str) -> SandboxEnvironment | None:
244
  '''
245
+ Determine Python sandbox environment based on install command and AST analysis.
246
  '''
247
  try:
248
  tree = ast.parse(code)
 
255
  except SyntaxError:
256
  pass
257
 
258
+ # Check install command for framework detection
259
+ if install_command and 'pygame' in install_command:
260
  return SandboxEnvironment.PYGAME
261
+ elif install_command and 'gradio' in install_command:
262
  return SandboxEnvironment.GRADIO
263
+ elif install_command and 'streamlit' in install_command:
264
  return SandboxEnvironment.STREAMLIT
265
+ # elif install_command and 'nicegui' in install_command:
266
  # return SandboxEnvironment.NICEGUI
267
 
268
  return SandboxEnvironment.PYTHON_RUNNER
269
 
270
 
271
+ def determine_jsts_environment(code: str, install_command: str) -> SandboxEnvironment | None:
272
  '''
273
+ Determine JavaScript/TypeScript sandbox environment based on install command and AST analysis.
274
  '''
275
  # First check for Vue SFC structure
276
  if '<template>' in code or '<script setup' in code:
277
  return SandboxEnvironment.VUE
278
 
279
+ # Check install command for framework detection
280
+ react_packages = {'react', '@react', 'next', '@next', '@tanstack/react-query', 'react-query'}
281
  vue_packages = {'vue', '@vue', 'nuxt', '@nuxt'}
282
 
283
+ if install_command and any(pkg in install_command for pkg in react_packages):
284
  return SandboxEnvironment.REACT
285
+ elif install_command and any(pkg in install_command for pkg in vue_packages):
286
  return SandboxEnvironment.VUE
287
 
288
  try:
 
345
  return SandboxEnvironment.VUE
346
 
347
  except Exception as e:
348
+ pass
349
 
350
  return SandboxEnvironment.JAVASCRIPT_RUNNER
351
 
 
434
  return 'typescript'
435
 
436
  except Exception as e:
437
+ pass
438
  # Fallback to basic checks if parsing fails
439
  pass
440
 
 
569
  return list(packages)
570
 
571
 
572
+ def extract_code_from_markdown(message: str, enable_auto_env: bool = False) -> tuple[str, str, SandboxEnvironment | None, str] | None:
573
  '''
574
  Extracts code from a markdown message by parsing code blocks directly.
575
  Determines sandbox environment based on code content and frameworks used.
576
 
577
  Returns:
578
+ tuple[str, str, SandboxEnvironment | None, str]: A tuple:
579
  1. code - the longest code block found
580
  2. code language
581
+ 3. sandbox environment determined from code content
582
+ 4. install_command - bash command from ```bash code blocks
583
  '''
584
  code_block_regex = r'```(?P<code_lang>[\w\+\#\-\.]*)?[ \t]*\r?\n?(?P<code>.*?)```'
585
  matches = list(re.finditer(code_block_regex, message, re.DOTALL))
 
591
  low_priority_languages = ['bash', 'shell',
592
  'sh', 'zsh', 'powershell', 'pwsh', '']
593
 
594
+ # Extract bash commands first
595
+ install_command = ""
596
+ bash_matches = [match for match in matches if (match.group('code_lang') or '').lower() in ['bash', 'shell', 'sh']]
597
+ if bash_matches:
598
+ # Use the first bash command found, or concatenate multiple if needed
599
+ install_command = bash_matches[0].group('code').strip()
600
+ if len(bash_matches) > 1:
601
+ # If multiple bash blocks, join them with && or newlines
602
+ install_command = ' && '.join([match.group('code').strip() for match in bash_matches])
603
+
604
  # Find the main code block by avoiding low-priority languages
605
+ main_code = ""
606
+ main_code_lang = ""
607
  max_length = 0
608
 
609
  for match in matches:
 
614
  main_code_lang = code_lang
615
  max_length = len(code)
616
 
 
 
 
 
 
617
 
618
  # Define language prefixes for each environment
619
  python_prefixes = ['py', 'ipython', 'pygame', 'gradio', 'streamlit']
 
630
  rust_prefixes = ['rust']
631
  csharp_prefixes = ['cs', 'csharp', 'dotnet']
632
 
 
 
 
 
633
  # Helper function to check if any prefix matches
634
  def matches_prefix(lang: str, prefixes: list[str]) -> bool:
635
  return any(lang.lower().startswith(prefix) for prefix in prefixes)
636
 
637
+ # Determine sandbox environment based on language
638
  if matches_prefix(main_code_lang, python_prefixes):
639
+ sandbox_env_name = determine_python_environment(main_code, install_command)
 
 
 
 
 
640
  elif matches_prefix(main_code_lang, vue_prefixes):
 
641
  sandbox_env_name = SandboxEnvironment.VUE
642
  main_code_lang = detect_js_ts_code_lang(main_code)
643
  elif matches_prefix(main_code_lang, react_prefixes):
 
644
  sandbox_env_name = SandboxEnvironment.REACT
645
  main_code_lang = detect_js_ts_code_lang(main_code)
646
  elif ('<!DOCTYPE html>' in main_code and ('<head' in main_code or '<body' in main_code)) or (main_code.strip().startswith('<svg')) or (not matches_prefix(main_code_lang, [*react_prefixes, *vue_prefixes, *js_prefixes, *ts_prefixes]) and ('<html' in main_code or '<!DOCTYPE html>' in main_code)):
 
647
  sandbox_env_name = SandboxEnvironment.HTML
648
  main_code_lang = 'html'
649
  elif matches_prefix(main_code_lang, js_prefixes):
650
  main_code_lang = 'javascript'
651
+ sandbox_env_name = determine_jsts_environment(main_code, install_command)
 
652
  elif matches_prefix(main_code_lang, ts_prefixes):
653
  main_code_lang = 'typescript'
654
+ sandbox_env_name = determine_jsts_environment(main_code, install_command)
 
655
  elif matches_prefix(main_code_lang, html_prefixes):
656
  main_code_lang = detect_js_ts_code_lang(main_code)
657
+ sandbox_env_name = SandboxEnvironment.HTML
 
658
  elif matches_prefix(main_code_lang, mermaid_prefixes):
659
  main_code_lang = 'markdown'
660
  sandbox_env_name = SandboxEnvironment.MERMAID
 
672
  sandbox_env_name = SandboxEnvironment.RUST_RUNNER
673
  elif main_code_lang == 'c':
674
  main_code_lang = 'c'
675
+ sandbox_env_name = SandboxEnvironment.C_RUNNER
676
  else:
677
  sandbox_env_name = None
678
 
 
 
 
 
 
 
 
 
 
 
 
679
  if not main_code_lang:
680
  main_code_lang = 'markdown'
681
 
682
+ return main_code, main_code_lang, sandbox_env_name, install_command
683
 
684
 
685
  def create_placeholder_svg_data_url(width: int, height: int) -> str:
 
715
  encoded_svg = base64.b64encode(svg.encode('utf-8')).decode('utf-8')
716
  return f'data:image/svg+xml;base64,{encoded_svg}'
717
  except Exception as e:
718
+ pass
719
  # Fallback to a simple colored div
720
  return f'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0ie3dpZHRofSIgaGVpZ2h0PSJ7aGVpZ2h0fSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZjNmNGY2Ii8+PC9zdmc+'
721
 
 
740
 
741
  # Validate dimensions
742
  if width <= 0 or height <= 0:
743
+ pass
744
  width, height = 100, 100
745
  elif width > 10000 or height > 10000:
746
+ pass
747
  width, height = min(width, 1000), min(height, 1000)
748
 
749
+ pass
750
  data_url = create_placeholder_svg_data_url(width, height)
751
  return data_url
752
  except Exception as e:
753
+ pass
754
  # Return a simple fallback
755
  return 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZjNmNGY2Ii8+PC9zdmc+'
756
 
 
760
  try:
761
  # Replace all occurrences
762
  result = re.sub(pattern, replacer, code)
763
+ pass
764
  return result
765
  except Exception as e:
766
+ pass
767
  return code # Return original code if replacement fails
768
 
769
 
sandbox/code_runner.py CHANGED
@@ -6,6 +6,7 @@ Gradio will interact with this module.
6
 
7
  from typing import Any, Generator, Literal, TypeAlias, TypedDict, Set
8
  import uuid
 
9
  import gradio as gr
10
 
11
  import base64
@@ -124,7 +125,7 @@ def create_chatbot_sandbox_state(btn_list_length: int = 5) -> ChatbotSandboxStat
124
  'sandbox_instruction': DEFAULT_SANDBOX_INSTRUCTIONS[SandboxEnvironment.AUTO],
125
  'code_to_execute': "",
126
  'code_language': None,
127
- 'code_dependencies': ([], []),
128
  'btn_list_length': btn_list_length,
129
  'sandbox_id': None,
130
  'chat_session_id': None,
@@ -162,7 +163,7 @@ def reset_sandbox_state(state: ChatbotSandboxState) -> ChatbotSandboxState:
162
  state['sandbox_instruction'] = DEFAULT_SANDBOX_INSTRUCTIONS[SandboxEnvironment.AUTO]
163
  state['code_to_execute'] = ""
164
  state['code_language'] = None
165
- state['code_dependencies'] = ([], [])
166
  state['sandbox_error'] = None
167
  state['sandbox_output'] = None
168
 
@@ -369,7 +370,7 @@ def render_result(result):
369
  return str(result)
370
 
371
 
372
- def run_code_interpreter(code: str, code_language: str | None, code_dependencies: tuple[list[str], list[str]]) -> tuple[str, str]:
373
  """
374
  Executes the provided code within a sandboxed environment and returns the output.
375
 
@@ -378,18 +379,19 @@ def run_code_interpreter(code: str, code_language: str | None, code_dependencies
378
  """
379
  sandbox = CodeSandbox()
380
 
381
- sandbox.commands.run("pip install uv",
382
- timeout=60 * 3,
383
- on_stderr=lambda message: print(message),)
384
-
385
  stderrs = []
386
 
387
- python_dependencies, npm_dependencies = code_dependencies
388
- pip_install_errs = install_pip_dependencies(sandbox, python_dependencies)
389
- npm_install_errs = install_npm_dependencies(sandbox, npm_dependencies)
390
-
391
- stderrs.extend(pip_install_errs)
392
- stderrs.extend(npm_install_errs)
 
 
 
 
 
393
 
394
  execution = sandbox.run_code(
395
  code=code,
@@ -403,7 +405,7 @@ def run_code_interpreter(code: str, code_language: str | None, code_dependencies
403
  stderr += f"\n{execution.error.name}: {execution.error.value}"
404
  output = ""
405
  if stdout:
406
- output += f"### Stdout:\n```markdown\n{stdout}\n```\n\n"
407
 
408
  stderrs.append(stderr)
409
 
@@ -425,14 +427,14 @@ def run_code_interpreter(code: str, code_language: str | None, code_dependencies
425
  return output, "" if output else stderrs
426
 
427
 
428
- def run_html_sandbox(code: str, code_dependencies: tuple[list[str], list[str]], existing_sandbox_id: str | None = None) -> tuple[str, str, str]:
429
  """
430
  Executes the provided code within a sandboxed environment and returns the output.
431
  Supports both React and Vue.js rendering in HTML files.
432
 
433
  Args:
434
  code (str): The code to be executed.
435
- code_dependencies: Tuple of (python_deps, npm_deps)
436
 
437
  Returns:
438
  tuple: (sandbox_url, sandbox_id, stderr)
@@ -441,9 +443,16 @@ def run_html_sandbox(code: str, code_dependencies: tuple[list[str], list[str]],
441
  project_root = "~/html_app"
442
  sandbox.files.make_dir(project_root)
443
 
444
- # HTML does not support dependencies for now
445
- # _, npm_dependencies = code_dependencies
446
- # install_npm_dependencies(sandbox, npm_dependencies, project_root=project_root)
 
 
 
 
 
 
 
447
 
448
  # replace placeholder URLs with SVG data URLs
449
  code = replace_placeholder_urls(code)
@@ -455,12 +464,13 @@ def run_html_sandbox(code: str, code_dependencies: tuple[list[str], list[str]],
455
  return (sandbox_url, sandbox.sandbox_id, '')
456
 
457
 
458
- def run_react_sandbox(code: str, code_dependencies: tuple[list[str], list[str]], existing_sandbox_id: str | None = None) -> CodeRunResult:
459
  """
460
  Executes the provided code within a sandboxed environment and returns the output.
461
 
462
  Args:
463
  code (str): The code to be executed.
 
464
 
465
  Returns:
466
  url for remote sandbox
@@ -470,22 +480,31 @@ def run_react_sandbox(code: str, code_dependencies: tuple[list[str], list[str]],
470
 
471
  stderrs: list[str] = [] # to collect errors
472
 
473
- _, npm_dependencies = code_dependencies
474
- if npm_dependencies:
475
- print(f"Installing NPM dependencies...: {npm_dependencies}")
476
- install_errs = install_npm_dependencies(sandbox, npm_dependencies, project_root=project_root)
477
- stderrs.extend(install_errs)
478
- print("NPM dependencies installed. " + "Errors: " + str(install_errs))
479
-
480
  # replace placeholder URLs with SVG data URLs
481
  code = replace_placeholder_urls(code)
482
 
483
- # set up the sandbox
484
  print("Setting up sandbox directory structure...")
485
  file_path = "~/react_app/src/App.tsx"
486
  sandbox.files.write(file_path, code, "user", 60)
487
  print("Code files written successfully.")
488
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
489
  is_run_success, _, build_stderrs = run_command_in_sandbox(
490
  sandbox=sandbox,
491
  command="npm run build --loglevel=error -- --mode development --logLevel error",
@@ -493,7 +512,13 @@ def run_react_sandbox(code: str, code_dependencies: tuple[list[str], list[str]],
493
  )
494
  stderrs.extend(build_stderrs)
495
 
 
496
  sandbox_url = get_sandbox_app_url(sandbox, 'react')
 
 
 
 
 
497
  return {
498
  'sandbox_id': sandbox.sandbox_id,
499
  'sandbox_url': sandbox_url,
@@ -502,12 +527,13 @@ def run_react_sandbox(code: str, code_dependencies: tuple[list[str], list[str]],
502
  }
503
 
504
 
505
- def run_vue_sandbox(code: str, code_dependencies: tuple[list[str], list[str]], existing_sandbox_id: str | None = None) -> CodeRunResult:
506
  """
507
  Executes the provided Vue code within a sandboxed environment and returns the output.
508
 
509
  Args:
510
  code (str): The Vue code to be executed.
 
511
 
512
  Returns:
513
  url for remote sandbox
@@ -520,17 +546,26 @@ def run_vue_sandbox(code: str, code_dependencies: tuple[list[str], list[str]], e
520
  # replace placeholder URLs with SVG data URLs
521
  code = replace_placeholder_urls(code)
522
 
523
- # Set up the sandbox
524
  file_path = "~/vue_app/src/App.vue"
525
  sandbox.files.write(file_path, code, "user", 60)
526
 
527
- _, npm_dependencies = code_dependencies
528
- if npm_dependencies:
529
- print(f"Installing NPM dependencies...: {npm_dependencies}")
530
- install_errs = install_npm_dependencies(sandbox, npm_dependencies, project_root=project_root)
531
- stderrs.extend(install_errs)
532
- print("NPM dependencies installed. " + "Errors: " + str(install_errs))
533
-
 
 
 
 
 
 
 
 
 
534
  is_run_success, _, build_stderrs = run_command_in_sandbox(
535
  sandbox=sandbox,
536
  command="npm run build --loglevel=error -- --mode development --logLevel error",
@@ -538,7 +573,14 @@ def run_vue_sandbox(code: str, code_dependencies: tuple[list[str], list[str]], e
538
  )
539
  stderrs.extend(build_stderrs)
540
 
 
541
  sandbox_url = get_sandbox_app_url(sandbox, 'vue')
 
 
 
 
 
 
542
  return {
543
  'sandbox_id': sandbox.sandbox_id,
544
  'sandbox_url': sandbox_url,
@@ -547,12 +589,13 @@ def run_vue_sandbox(code: str, code_dependencies: tuple[list[str], list[str]], e
547
  }
548
 
549
 
550
- def run_pygame_sandbox(code: str, code_dependencies: tuple[list[str], list[str]], existing_sandbox_id: str | None = None) -> CodeRunResult:
551
  """
552
  Executes the provided code within a sandboxed environment and returns the output.
553
 
554
  Args:
555
  code (str): The code to be executed.
 
556
 
557
  Returns:
558
  url for remote sandbox
@@ -563,20 +606,39 @@ def run_pygame_sandbox(code: str, code_dependencies: tuple[list[str], list[str]]
563
 
564
  stderrs = []
565
 
 
566
  sandbox.files.write(file_path, code, "user", 60)
567
 
568
- python_dependencies, _ = code_dependencies
569
- install_errs = install_pip_dependencies(sandbox, python_dependencies)
570
- stderrs.extend(install_errs)
571
-
572
- # build the pygame code
 
 
 
 
 
 
 
 
 
 
 
573
  is_run_success, _, build_stderrs = run_command_in_sandbox(
574
  sandbox=sandbox,
575
  command="pygbag --build ~/pygame_app",
576
  )
577
  stderrs.extend(build_stderrs)
578
 
 
579
  sandbox_url = get_sandbox_app_url(sandbox, 'pygame')
 
 
 
 
 
 
580
  return {
581
  'sandbox_id': sandbox.sandbox_id,
582
  'sandbox_url': sandbox_url,
@@ -585,12 +647,13 @@ def run_pygame_sandbox(code: str, code_dependencies: tuple[list[str], list[str]]
585
  }
586
 
587
 
588
- def run_gradio_sandbox(code: str, code_dependencies: tuple[list[str], list[str]], existing_sandbox_id: str | None = None) -> tuple[str, str, str]:
589
  """
590
  Executes the provided code within a sandboxed environment and returns the output.
591
 
592
  Args:
593
  code (str): The code to be executed.
 
594
 
595
  Returns:
596
  url for remote sandbox and sandbox id
@@ -602,9 +665,18 @@ def run_gradio_sandbox(code: str, code_dependencies: tuple[list[str], list[str]]
602
 
603
  stderrs = []
604
 
605
- python_dependencies, _ = code_dependencies
606
- install_stderr = install_pip_dependencies(sandbox, python_dependencies)
607
- stderrs.extend(install_stderr)
 
 
 
 
 
 
 
 
 
608
 
609
  stderr = run_background_command_with_timeout(
610
  sandbox,
@@ -618,7 +690,7 @@ def run_gradio_sandbox(code: str, code_dependencies: tuple[list[str], list[str]]
618
  return (sandbox_url, sandbox.sandbox_id, '\n'.join(stderrs))
619
 
620
 
621
- def run_streamlit_sandbox(code: str, code_dependencies: tuple[list[str], list[str]], existing_sandbox_id: str | None = None) -> tuple[str, str, str]:
622
  sandbox = reuse_or_create_sandbox(sandbox_id=existing_sandbox_id)
623
 
624
  stderrs = []
@@ -627,9 +699,18 @@ def run_streamlit_sandbox(code: str, code_dependencies: tuple[list[str], list[st
627
  file_path = "~/mystreamlit/app.py"
628
  sandbox.files.write(file_path, code, "user", 60)
629
 
630
- python_dependencies, _ = code_dependencies
631
- install_stderr = install_pip_dependencies(sandbox, python_dependencies)
632
- stderrs.extend(install_stderr)
 
 
 
 
 
 
 
 
 
633
 
634
  stderr = run_background_command_with_timeout(
635
  sandbox,
@@ -825,70 +906,11 @@ def on_edit_code(
825
  return
826
  sandbox_state['code_to_execute'] = sandbox_code
827
 
828
- # Extract packages from imports (without versions)
829
- python_deps_from_imports = set(extract_python_imports(sandbox_code))
830
- npm_deps_from_imports = set(extract_js_imports(sandbox_code))
831
-
832
- # Get existing dependencies with versions from state
833
- existing_python_deps, existing_npm_deps = sandbox_state["code_dependencies"]
834
-
835
- # Create dictionaries to track package versions
836
- python_deps_dict = {} # pkg_name -> version
837
- npm_deps_dict = {} # pkg_name -> version
838
-
839
- # First add existing dependencies with their specific versions
840
- for dep in existing_python_deps:
841
- pkg_name = dep.split('==')[0].split('>=')[0].split('<=')[0].split('~=')[0]
842
- version = dep[len(pkg_name):]
843
- if version: # If it has a specific version
844
- python_deps_dict[pkg_name] = version
845
- elif pkg_name in python_deps_from_imports: # Only keep packages that are still imported
846
- python_deps_dict[pkg_name] = "latest"
847
-
848
- for dep in existing_npm_deps:
849
- if '@' in dep and not dep.startswith('@'):
850
- pkg_name = dep.split('@')[0]
851
- version = '@' + dep.split('@')[1]
852
- elif '@' in dep[1:]: # Handle scoped packages
853
- pkg_name, version = dep.rsplit('@', 1)
854
- version = '@' + version
855
- else:
856
- pkg_name = dep
857
- version = "latest"
858
- if version != "latest": # If it has a specific version
859
- npm_deps_dict[pkg_name] = version
860
- elif pkg_name in npm_deps_from_imports: # Only keep packages that are still imported
861
- npm_deps_dict[pkg_name] = "latest"
862
-
863
- # Add new dependencies from imports with "latest" if not already present
864
- for dep in python_deps_from_imports:
865
- if dep not in python_deps_dict:
866
- python_deps_dict[dep] = "latest"
867
-
868
- for dep in npm_deps_from_imports:
869
- if dep not in npm_deps_dict:
870
- npm_deps_dict[dep] = "latest"
871
-
872
- # Convert to dataframe format
873
- dependencies = []
874
-
875
- # Add Python packages
876
- for pkg_name, version in python_deps_dict.items():
877
- dependencies.append(["python", pkg_name, version])
878
-
879
- # Add NPM packages
880
- for pkg_name, version in npm_deps_dict.items():
881
- dependencies.append(["npm", pkg_name, version])
882
-
883
- # If no dependencies found, provide default empty rows
884
- if not dependencies:
885
- dependencies = [["python", "", ""], ["npm", "", ""]]
886
-
887
- # Update dependencies in sandbox state
888
- sandbox_state["code_dependencies"] = (
889
- [f"{pkg}{ver}" if ver != "latest" else pkg for pkg, ver in python_deps_dict.items()],
890
- [f"{pkg}{ver}" if ver != "latest" else pkg for pkg, ver in npm_deps_dict.items()]
891
- )
892
 
893
  yield (
894
  gr.skip(), # sandbox_output_md
@@ -964,8 +986,9 @@ def on_edit_dependency(
964
  else:
965
  npm_deps.append(pkg_name)
966
 
967
- # Update sandbox state with new dependencies
968
- sandbox_state["code_dependencies"] = (python_deps, npm_deps)
 
969
 
970
  # increase edit round
971
  sandbox_state['edit_round'] += 1
@@ -1019,7 +1042,7 @@ def on_click_code_message_run(
1019
  yield gr.skip(), gr.skip(), gr.skip(), gr.skip()
1020
  return
1021
 
1022
- code, code_language, code_dependencies, env_selection = extract_result
1023
 
1024
  # As sandbox is reused, no need to skip
1025
  # if sandbox_state['code_to_execute'] == code and sandbox_state['code_language'] == code_language:
@@ -1034,43 +1057,12 @@ def on_click_code_message_run(
1034
  # ensure gradio supports the code language
1035
  ) in VALID_GRADIO_CODE_LANGUAGES else None
1036
 
1037
- python_deps, npm_deps = code_dependencies
1038
-
1039
- # Convert to dataframe format
1040
- dependencies = []
1041
-
1042
- # Add Python packages with versions
1043
- for dep in python_deps:
1044
- # Check if package has version specifier
1045
- if any(op in dep for op in ['==', '>=', '<=', '~=']):
1046
- # Split on first occurrence of version operator
1047
- pkg_name = dep.split('==')[0].split('>=')[0].split('<=')[0].split('~=')[0]
1048
- version = dep[len(pkg_name):] # Get everything after package name
1049
- dependencies.append(["python", pkg_name, version])
1050
- else:
1051
- dependencies.append(["python", dep, "latest"])
1052
-
1053
- # Add NPM packages with versions
1054
- for dep in npm_deps:
1055
- # Check if package has version specifier
1056
- if '@' in dep and not dep.startswith('@'):
1057
- # Handle non-scoped packages with version
1058
- pkg_name, version = dep.split('@', 1)
1059
- dependencies.append(["npm", pkg_name, '@' + version])
1060
- elif '@' in dep[1:]: # Handle scoped packages with version
1061
- # Split on last @ for scoped packages
1062
- pkg_parts = dep.rsplit('@', 1)
1063
- dependencies.append(["npm", pkg_parts[0], '@' + pkg_parts[1]])
1064
- else:
1065
- dependencies.append(["npm", dep, "latest"])
1066
-
1067
- # If no dependencies found, provide default empty rows
1068
- if not dependencies:
1069
- dependencies = [["python", "", ""], ["npm", "", ""]]
1070
 
1071
  sandbox_state['code_to_execute'] = code
1072
  sandbox_state['code_language'] = code_language
1073
- sandbox_state["code_dependencies"] = code_dependencies
1074
  if sandbox_state['sandbox_environment'] == SandboxEnvironment.AUTO:
1075
  sandbox_state['auto_selected_sandbox_environment'] = env_selection
1076
 
@@ -1137,66 +1129,11 @@ def on_run_code(
1137
  # ensure gradio supports the code language
1138
  ) in VALID_GRADIO_CODE_LANGUAGES else None
1139
 
1140
- # Use dependencies from sandbox_state instead of re-extracting
1141
- code_dependencies = sandbox_state['code_dependencies']
1142
- python_deps, npm_deps = code_dependencies
1143
-
1144
- # Helper function to extract package name without version
1145
- def get_base_package_name(pkg: str) -> str:
1146
- # For Python packages
1147
- if any(op in pkg for op in ['==', '>=', '<=', '~=', '>', '<']):
1148
- return pkg.split('==')[0].split('>=')[0].split('<=')[0].split('~=')[0].split('>')[0].split('<')[0]
1149
- # For NPM packages
1150
- if '@' in pkg and not pkg.startswith('@'):
1151
- return pkg.split('@')[0]
1152
- elif '@' in pkg[1:]: # Handle scoped packages
1153
- return pkg.rsplit('@', 1)[0]
1154
- return pkg
1155
-
1156
- # Helper function to extract version from package string
1157
- def get_package_version(pkg: str) -> str:
1158
- # For Python packages
1159
- if any(op in pkg for op in ['==', '>=', '<=', '~=', '>', '<']):
1160
- base_name = get_base_package_name(pkg)
1161
- return pkg[len(base_name):]
1162
- # For NPM packages
1163
- if '@' in pkg and not pkg.startswith('@'):
1164
- return '@' + pkg.split('@', 1)[1]
1165
- elif '@' in pkg[1:]: # Handle scoped packages
1166
- _, version = pkg.rsplit('@', 1)
1167
- return '@' + version
1168
- return "latest"
1169
-
1170
- # Create unified dependency dictionaries to avoid duplicates
1171
- python_deps_dict = {} # pkg_name -> version
1172
- npm_deps_dict = {} # pkg_name -> version
1173
-
1174
- # Process Python dependencies
1175
- for dep in python_deps:
1176
- base_name = get_base_package_name(dep)
1177
- version = get_package_version(dep)
1178
- # Only update if we don't have a version yet or if we're replacing 'latest'
1179
- if base_name not in python_deps_dict or python_deps_dict[base_name] == "latest":
1180
- python_deps_dict[base_name] = version
1181
-
1182
- # Process NPM dependencies
1183
- for dep in npm_deps:
1184
- base_name = get_base_package_name(dep)
1185
- version = get_package_version(dep)
1186
- # Only update if we don't have a version yet or if we're replacing 'latest'
1187
- if base_name not in npm_deps_dict or npm_deps_dict[base_name] == "latest":
1188
- npm_deps_dict[base_name] = version
1189
-
1190
- # Convert unified dictionaries to dataframe format
1191
- dependencies = []
1192
- for pkg_name, version in python_deps_dict.items():
1193
- dependencies.append(["python", pkg_name, version])
1194
- for pkg_name, version in npm_deps_dict.items():
1195
- dependencies.append(["npm", pkg_name, version])
1196
-
1197
- # If no dependencies found, provide default empty rows
1198
- if not dependencies:
1199
- dependencies = [["python", "", ""], ["npm", "", ""]]
1200
 
1201
  # Initialize output with loading message
1202
  markdown_output_text = "### Sandbox Execution Log\n\n"
@@ -1237,12 +1174,12 @@ def on_run_code(
1237
  yield update_markdown_output("🔄 Setting up HTML sandbox...")
1238
  sandbox_url, sandbox_id, sandbox_error = run_html_sandbox(
1239
  code=code,
1240
- code_dependencies=code_dependencies,
1241
  existing_sandbox_id=sandbox_state['sandbox_id'],
1242
  )
1243
  if sandbox_error:
1244
  yield update_markdown_output("❌ HTML sandbox failed to run!", clear_output=True)
1245
- yield update_markdown_output(f"### Stderr:\n```markdown\n{sandbox_error}\n```\n\n")
1246
  else:
1247
  yield update_markdown_output("✅ HTML sandbox is ready!", clear_output=True)
1248
  yield (
@@ -1260,13 +1197,13 @@ def on_run_code(
1260
  yield update_markdown_output("🔄 Setting up React sandbox...")
1261
  code_run_result = run_react_sandbox(
1262
  code=code,
1263
- code_dependencies=code_dependencies,
1264
  existing_sandbox_id=sandbox_state['sandbox_id'],
1265
  )
1266
  sandbox_id, sandbox_error = code_run_result['sandbox_id'], code_run_result['stderr']
1267
  if code_run_result['is_run_success'] is False and sandbox_error:
1268
  yield update_markdown_output("❌ React sandbox failed to run!", clear_output=True)
1269
- yield update_markdown_output(f"### Stderr:\n```markdown\n{sandbox_error}\n```\n\n")
1270
  else:
1271
  yield update_markdown_output("✅ React sandbox is ready!", clear_output=True)
1272
  yield (
@@ -1284,13 +1221,13 @@ def on_run_code(
1284
  yield update_markdown_output("🔄 Setting up Vue sandbox...")
1285
  code_run_result = run_vue_sandbox(
1286
  code=code,
1287
- code_dependencies=code_dependencies,
1288
  existing_sandbox_id=sandbox_state['sandbox_id'],
1289
  )
1290
  sandbox_id, sandbox_error = code_run_result['sandbox_id'], code_run_result['stderr']
1291
  if code_run_result['is_run_success'] is False and code_run_result['stderr']:
1292
  yield update_markdown_output("❌ Vue sandbox failed to run!", clear_output=True)
1293
- yield update_markdown_output(f"### Stderr:\n```markdown\n{code_run_result['stderr']}\n```\n\n")
1294
  else:
1295
  yield update_markdown_output("✅ Vue sandbox is ready!", clear_output=True)
1296
  yield (
@@ -1308,13 +1245,13 @@ def on_run_code(
1308
  yield update_markdown_output("🔄 Setting up PyGame sandbox...")
1309
  code_run_result = run_pygame_sandbox(
1310
  code=code,
1311
- code_dependencies=code_dependencies,
1312
  existing_sandbox_id=sandbox_state['sandbox_id'],
1313
  )
1314
  sandbox_id, sandbox_error = code_run_result['sandbox_id'], code_run_result['stderr']
1315
  if code_run_result['is_run_success'] is False and code_run_result['stderr']:
1316
  yield update_markdown_output("❌ PyGame sandbox failed to run!", clear_output=True)
1317
- yield update_markdown_output(f"### Stderr:\n```markdown\n{code_run_result['stderr']}\n```\n\n")
1318
  else:
1319
  yield update_markdown_output("✅ PyGame sandbox is ready!", clear_output=True)
1320
  yield (
@@ -1332,12 +1269,12 @@ def on_run_code(
1332
  yield update_markdown_output("🔄 Setting up Gradio sandbox...")
1333
  sandbox_url, sandbox_id, sandbox_error = run_gradio_sandbox(
1334
  code=code,
1335
- code_dependencies=code_dependencies,
1336
  existing_sandbox_id=sandbox_state['sandbox_id'],
1337
  )
1338
  if sandbox_error:
1339
  yield update_markdown_output("❌ Gradio sandbox failed to run!", clear_output=True)
1340
- yield update_markdown_output(f"### Stderr:\n```markdown\n{sandbox_error}\n```\n\n")
1341
  else:
1342
  yield update_markdown_output("✅ Gradio sandbox is ready!", clear_output=True)
1343
  yield (
@@ -1355,12 +1292,12 @@ def on_run_code(
1355
  yield update_markdown_output("🔄 Setting up Streamlit sandbox...")
1356
  sandbox_url, sandbox_id, sandbox_error = run_streamlit_sandbox(
1357
  code=code,
1358
- code_dependencies=code_dependencies,
1359
  existing_sandbox_id=sandbox_state['sandbox_id'],
1360
  )
1361
  if sandbox_error:
1362
  yield update_markdown_output("❌ Streamlit sandbox failed to run!", clear_output=True)
1363
- yield update_markdown_output(f"### Stderr:\n```markdown\n{sandbox_error}\n```\n\n")
1364
  else:
1365
  yield update_markdown_output("✅ Streamlit sandbox is ready!", clear_output=True)
1366
  yield (
@@ -1380,12 +1317,12 @@ def on_run_code(
1380
  html_code = mermaid_to_html(code, theme='light')
1381
  sandbox_url, sandbox_id, sandbox_error = run_html_sandbox(
1382
  code=html_code,
1383
- code_dependencies=code_dependencies,
1384
  existing_sandbox_id=sandbox_state['sandbox_id'],
1385
  )
1386
  if sandbox_error:
1387
  yield update_markdown_output("❌ Mermaid visualization failed to render!", clear_output=True)
1388
- yield update_markdown_output(f"### Stderr:\n```markdown\n{sandbox_error}\n```\n\n")
1389
  else:
1390
  yield update_markdown_output("✅ Mermaid visualization is ready!", clear_output=True)
1391
  yield (
@@ -1402,11 +1339,11 @@ def on_run_code(
1402
  case SandboxEnvironment.PYTHON_RUNNER:
1403
  yield update_markdown_output("🔄 Running Python Runner...", clear_output=True)
1404
  sandbox_output, sandbox_error = run_code_interpreter(
1405
- code=code, code_language='python', code_dependencies=code_dependencies
1406
  )
1407
  if sandbox_error:
1408
  yield update_markdown_output("❌ Python Runner failed to run!", clear_output=True)
1409
- yield update_markdown_output(f"### Stderr:\n```markdown\n{sandbox_error}\n```\n\n")
1410
  else:
1411
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1412
  yield (
@@ -1426,25 +1363,30 @@ def on_run_code(
1426
  )
1427
  case SandboxEnvironment.JAVASCRIPT_RUNNER:
1428
  yield update_markdown_output("🔄 Running JavaScript Runner...", clear_output=True)
1429
- sandbox_output, sandbox_error = run_code_interpreter(
1430
- code=code, code_language='javascript', code_dependencies=code_dependencies
 
 
 
1431
  )
 
 
1432
  if sandbox_error:
1433
  yield update_markdown_output("❌ JavaScript Runner failed to run!", clear_output=True)
1434
- yield update_markdown_output(f"### Stderr:\n```markdown\n{sandbox_error}\n```\n\n")
1435
  else:
1436
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1437
  yield (
1438
  gr.Markdown(
1439
- value=markdown_output_text + "\n\n" + sandbox_output,
1440
  sanitize_html=False,
1441
  visible=True,
1442
  ),
1443
  SandboxComponent(
1444
- value=("", False, []),
1445
- label="Example",
1446
- visible=False,
1447
- key="newsandbox",
1448
  ),
1449
  gr.skip(),
1450
  gr.skip(),
@@ -1456,7 +1398,7 @@ def on_run_code(
1456
  )
1457
  if sandbox_error:
1458
  yield update_markdown_output("❌ C Runner failed to run!", clear_output=True)
1459
- yield update_markdown_output(f"### Stderr:\n```markdown\n{sandbox_error}\n```\n\n")
1460
  else:
1461
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1462
  yield (
@@ -1481,7 +1423,7 @@ def on_run_code(
1481
  )
1482
  if sandbox_error:
1483
  yield update_markdown_output("❌ C++ Runner failed to run!", clear_output=True)
1484
- yield update_markdown_output(f"### Stderr:\n```markdown\n{sandbox_error}\n```\n\n")
1485
  else:
1486
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1487
  yield (
@@ -1506,7 +1448,7 @@ def on_run_code(
1506
  )
1507
  if sandbox_error:
1508
  yield update_markdown_output("❌ Java Runner failed to run!", clear_output=True)
1509
- yield update_markdown_output(f"### Stderr:\n```markdown\n{sandbox_error}\n```\n\n")
1510
  else:
1511
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1512
  yield (
@@ -1531,7 +1473,7 @@ def on_run_code(
1531
  )
1532
  if sandbox_error:
1533
  yield update_markdown_output("❌ Go Runner failed to run!", clear_output=True)
1534
- yield update_markdown_output(f"### Stderr:\n```markdown\n{sandbox_error}\n```\n\n")
1535
  else:
1536
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1537
  yield (
@@ -1566,7 +1508,7 @@ def on_run_code(
1566
  )
1567
  if sandbox_error:
1568
  yield update_markdown_output("❌ Rust Runner failed to run!", clear_output=True)
1569
- yield update_markdown_output(f"### Stderr:\n```markdown\n{sandbox_error}\n```\n\n")
1570
  else:
1571
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1572
  yield (
 
6
 
7
  from typing import Any, Generator, Literal, TypeAlias, TypedDict, Set
8
  import uuid
9
+ import time
10
  import gradio as gr
11
 
12
  import base64
 
125
  'sandbox_instruction': DEFAULT_SANDBOX_INSTRUCTIONS[SandboxEnvironment.AUTO],
126
  'code_to_execute': "",
127
  'code_language': None,
128
+ 'install_command': "",
129
  'btn_list_length': btn_list_length,
130
  'sandbox_id': None,
131
  'chat_session_id': None,
 
163
  state['sandbox_instruction'] = DEFAULT_SANDBOX_INSTRUCTIONS[SandboxEnvironment.AUTO]
164
  state['code_to_execute'] = ""
165
  state['code_language'] = None
166
+ state['install_command'] = ""
167
  state['sandbox_error'] = None
168
  state['sandbox_output'] = None
169
 
 
370
  return str(result)
371
 
372
 
373
+ def run_code_interpreter(code: str, code_language: str | None, install_command: str) -> tuple[str, str]:
374
  """
375
  Executes the provided code within a sandboxed environment and returns the output.
376
 
 
379
  """
380
  sandbox = CodeSandbox()
381
 
 
 
 
 
382
  stderrs = []
383
 
384
+ # Run install command if provided
385
+ if install_command.strip():
386
+ is_success, stdout, stderr = run_command_in_sandbox(
387
+ sandbox=sandbox,
388
+ command=install_command,
389
+ timeout=60 * 3,
390
+ )
391
+ if stderr:
392
+ stderrs.extend(stderr)
393
+ if not is_success:
394
+ print(f"Install command failed: {stderr}")
395
 
396
  execution = sandbox.run_code(
397
  code=code,
 
405
  stderr += f"\n{execution.error.name}: {execution.error.value}"
406
  output = ""
407
  if stdout:
408
+ output += f"```markdown\n{stdout}\n```\n\n"
409
 
410
  stderrs.append(stderr)
411
 
 
427
  return output, "" if output else stderrs
428
 
429
 
430
+ def run_html_sandbox(code: str, install_command: str, existing_sandbox_id: str | None = None) -> tuple[str, str, str]:
431
  """
432
  Executes the provided code within a sandboxed environment and returns the output.
433
  Supports both React and Vue.js rendering in HTML files.
434
 
435
  Args:
436
  code (str): The code to be executed.
437
+ install_command (str): Bash command to install dependencies
438
 
439
  Returns:
440
  tuple: (sandbox_url, sandbox_id, stderr)
 
443
  project_root = "~/html_app"
444
  sandbox.files.make_dir(project_root)
445
 
446
+ # Run install command if provided
447
+ if install_command.strip():
448
+ is_success, stdout, stderr = run_command_in_sandbox(
449
+ sandbox=sandbox,
450
+ command=install_command,
451
+ timeout=60 * 3,
452
+ )
453
+ if not is_success:
454
+ print(f"Install command failed: {stderr}")
455
+ return "", sandbox.sandbox_id, '\n'.join(stderr)
456
 
457
  # replace placeholder URLs with SVG data URLs
458
  code = replace_placeholder_urls(code)
 
464
  return (sandbox_url, sandbox.sandbox_id, '')
465
 
466
 
467
+ def run_react_sandbox(code: str, install_command: str, existing_sandbox_id: str | None = None) -> CodeRunResult:
468
  """
469
  Executes the provided code within a sandboxed environment and returns the output.
470
 
471
  Args:
472
  code (str): The code to be executed.
473
+ install_command (str): Bash command to install dependencies
474
 
475
  Returns:
476
  url for remote sandbox
 
480
 
481
  stderrs: list[str] = [] # to collect errors
482
 
 
 
 
 
 
 
 
483
  # replace placeholder URLs with SVG data URLs
484
  code = replace_placeholder_urls(code)
485
 
486
+ # set up the sandbox directory structure first
487
  print("Setting up sandbox directory structure...")
488
  file_path = "~/react_app/src/App.tsx"
489
  sandbox.files.write(file_path, code, "user", 60)
490
  print("Code files written successfully.")
491
 
492
+ # Run install command AFTER setting up the project structure
493
+ if install_command.strip():
494
+ is_success, stdout, stderr = run_command_in_sandbox(
495
+ sandbox=sandbox,
496
+ command=install_command,
497
+ timeout=60 * 3,
498
+ working_directory=project_root, # Run in the correct directory
499
+ )
500
+ if stderr:
501
+ stderrs.extend(stderr)
502
+ if not is_success:
503
+ print(f"Install command failed: {stderr}")
504
+ # Don't return early - continue with build attempt
505
+ stderrs.append(f"Install command failed: {' '.join(stderr)}")
506
+
507
+ # Attempt to build the React app
508
  is_run_success, _, build_stderrs = run_command_in_sandbox(
509
  sandbox=sandbox,
510
  command="npm run build --loglevel=error -- --mode development --logLevel error",
 
512
  )
513
  stderrs.extend(build_stderrs)
514
 
515
+ # Always try to get the sandbox URL, even if build failed
516
  sandbox_url = get_sandbox_app_url(sandbox, 'react')
517
+
518
+ # If build failed but we have a sandbox, still return the URL
519
+ if not is_run_success and sandbox_url:
520
+ is_run_success = True # Consider it successful if we have a working sandbox
521
+
522
  return {
523
  'sandbox_id': sandbox.sandbox_id,
524
  'sandbox_url': sandbox_url,
 
527
  }
528
 
529
 
530
+ def run_vue_sandbox(code: str, install_command: str, existing_sandbox_id: str | None = None) -> CodeRunResult:
531
  """
532
  Executes the provided Vue code within a sandboxed environment and returns the output.
533
 
534
  Args:
535
  code (str): The Vue code to be executed.
536
+ install_command (str): Bash command to install dependencies
537
 
538
  Returns:
539
  url for remote sandbox
 
546
  # replace placeholder URLs with SVG data URLs
547
  code = replace_placeholder_urls(code)
548
 
549
+ # Set up the sandbox directory structure first
550
  file_path = "~/vue_app/src/App.vue"
551
  sandbox.files.write(file_path, code, "user", 60)
552
 
553
+ # Run install command AFTER setting up the project structure
554
+ if install_command.strip():
555
+ is_success, stdout, stderr = run_command_in_sandbox(
556
+ sandbox=sandbox,
557
+ command=install_command,
558
+ timeout=60 * 3,
559
+ working_directory=project_root, # Run in the correct directory
560
+ )
561
+ if stderr:
562
+ stderrs.extend(stderr)
563
+ if not is_success:
564
+ print(f"Install command failed: {stderr}")
565
+ # Don't return early - continue with build attempt
566
+ stderrs.append(f"Install command failed: {' '.join(stderr)}")
567
+
568
+ # Attempt to build the Vue app
569
  is_run_success, _, build_stderrs = run_command_in_sandbox(
570
  sandbox=sandbox,
571
  command="npm run build --loglevel=error -- --mode development --logLevel error",
 
573
  )
574
  stderrs.extend(build_stderrs)
575
 
576
+ # Always try to get the sandbox URL, even if build failed
577
  sandbox_url = get_sandbox_app_url(sandbox, 'vue')
578
+
579
+ # If build failed but we have a sandbox, still return the URL
580
+ if not is_run_success and sandbox_url:
581
+ print(f"⚠️ Build failed but sandbox is available at: {sandbox_url}")
582
+ is_run_success = True # Consider it successful if we have a working sandbox
583
+
584
  return {
585
  'sandbox_id': sandbox.sandbox_id,
586
  'sandbox_url': sandbox_url,
 
589
  }
590
 
591
 
592
+ def run_pygame_sandbox(code: str, install_command: str, existing_sandbox_id: str | None = None) -> CodeRunResult:
593
  """
594
  Executes the provided code within a sandboxed environment and returns the output.
595
 
596
  Args:
597
  code (str): The code to be executed.
598
+ install_command (str): Bash command to install dependencies
599
 
600
  Returns:
601
  url for remote sandbox
 
606
 
607
  stderrs = []
608
 
609
+ # Set up the sandbox directory structure first
610
  sandbox.files.write(file_path, code, "user", 60)
611
 
612
+ # Run install command AFTER setting up the project structure
613
+ if install_command.strip():
614
+ is_success, stdout, stderr = run_command_in_sandbox(
615
+ sandbox=sandbox,
616
+ command=install_command,
617
+ timeout=60 * 3,
618
+ working_directory=project_root, # Run in the correct directory
619
+ )
620
+ if stderr:
621
+ stderrs.extend(stderr)
622
+ if not is_success:
623
+ print(f"Install command failed: {stderr}")
624
+ # Don't return early - continue with build attempt
625
+ stderrs.append(f"Install command failed: {' '.join(stderr)}")
626
+
627
+ # Attempt to build the pygame code
628
  is_run_success, _, build_stderrs = run_command_in_sandbox(
629
  sandbox=sandbox,
630
  command="pygbag --build ~/pygame_app",
631
  )
632
  stderrs.extend(build_stderrs)
633
 
634
+ # Always try to get the sandbox URL, even if build failed
635
  sandbox_url = get_sandbox_app_url(sandbox, 'pygame')
636
+
637
+ # If build failed but we have a sandbox, still return the URL
638
+ if not is_run_success and sandbox_url:
639
+ print(f"⚠️ Build failed but sandbox is available at: {sandbox_url}")
640
+ is_run_success = True # Consider it successful if we have a working sandbox
641
+
642
  return {
643
  'sandbox_id': sandbox.sandbox_id,
644
  'sandbox_url': sandbox_url,
 
647
  }
648
 
649
 
650
+ def run_gradio_sandbox(code: str, install_command: str, existing_sandbox_id: str | None = None) -> tuple[str, str, str]:
651
  """
652
  Executes the provided code within a sandboxed environment and returns the output.
653
 
654
  Args:
655
  code (str): The code to be executed.
656
+ install_command (str): Bash command to install dependencies
657
 
658
  Returns:
659
  url for remote sandbox and sandbox id
 
665
 
666
  stderrs = []
667
 
668
+ # Run install command if provided
669
+ if install_command.strip():
670
+ is_success, stdout, stderr = run_command_in_sandbox(
671
+ sandbox=sandbox,
672
+ command=install_command,
673
+ timeout=60 * 3,
674
+ )
675
+ if stderr:
676
+ stderrs.extend(stderr)
677
+ if not is_success:
678
+ print(f"Install command failed: {stderr}")
679
+ return "", sandbox.sandbox_id, '\n'.join(stderr)
680
 
681
  stderr = run_background_command_with_timeout(
682
  sandbox,
 
690
  return (sandbox_url, sandbox.sandbox_id, '\n'.join(stderrs))
691
 
692
 
693
+ def run_streamlit_sandbox(code: str, install_command: str, existing_sandbox_id: str | None = None) -> tuple[str, str, str]:
694
  sandbox = reuse_or_create_sandbox(sandbox_id=existing_sandbox_id)
695
 
696
  stderrs = []
 
699
  file_path = "~/mystreamlit/app.py"
700
  sandbox.files.write(file_path, code, "user", 60)
701
 
702
+ # Run install command if provided
703
+ if install_command.strip():
704
+ is_success, stdout, stderr = run_command_in_sandbox(
705
+ sandbox=sandbox,
706
+ command=install_command,
707
+ timeout=60 * 3,
708
+ )
709
+ if stderr:
710
+ stderrs.extend(stderr)
711
+ if not is_success:
712
+ print(f"Install command failed: {stderr}")
713
+ return "", sandbox.sandbox_id, '\n'.join(stderr)
714
 
715
  stderr = run_background_command_with_timeout(
716
  sandbox,
 
906
  return
907
  sandbox_state['code_to_execute'] = sandbox_code
908
 
909
+ # Create empty dependencies dataframe for UI compatibility
910
+ dependencies = [["python", "", ""], ["npm", "", ""]]
911
+
912
+ # Keep existing install command
913
+ # No need to update install_command here as it's set from the original message
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
914
 
915
  yield (
916
  gr.skip(), # sandbox_output_md
 
986
  else:
987
  npm_deps.append(pkg_name)
988
 
989
+ # Update sandbox state with new install command
990
+ # For now, we'll keep the existing install_command as dependency editing is simplified
991
+ # In a full implementation, you might want to convert the dependency edits to install commands
992
 
993
  # increase edit round
994
  sandbox_state['edit_round'] += 1
 
1042
  yield gr.skip(), gr.skip(), gr.skip(), gr.skip()
1043
  return
1044
 
1045
+ code, code_language, env_selection, install_command = extract_result
1046
 
1047
  # As sandbox is reused, no need to skip
1048
  # if sandbox_state['code_to_execute'] == code and sandbox_state['code_language'] == code_language:
 
1057
  # ensure gradio supports the code language
1058
  ) in VALID_GRADIO_CODE_LANGUAGES else None
1059
 
1060
+ # Create empty dependencies dataframe for UI compatibility
1061
+ dependencies = [["python", "", ""], ["npm", "", ""]]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1062
 
1063
  sandbox_state['code_to_execute'] = code
1064
  sandbox_state['code_language'] = code_language
1065
+ sandbox_state['install_command'] = install_command
1066
  if sandbox_state['sandbox_environment'] == SandboxEnvironment.AUTO:
1067
  sandbox_state['auto_selected_sandbox_environment'] = env_selection
1068
 
 
1129
  # ensure gradio supports the code language
1130
  ) in VALID_GRADIO_CODE_LANGUAGES else None
1131
 
1132
+ # Get install command from sandbox state
1133
+ install_command = sandbox_state.get('install_command', '')
1134
+
1135
+ # Create empty dependencies dataframe for UI compatibility
1136
+ dependencies = [["python", "", ""], ["npm", "", ""]]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1137
 
1138
  # Initialize output with loading message
1139
  markdown_output_text = "### Sandbox Execution Log\n\n"
 
1174
  yield update_markdown_output("🔄 Setting up HTML sandbox...")
1175
  sandbox_url, sandbox_id, sandbox_error = run_html_sandbox(
1176
  code=code,
1177
+ install_command=install_command,
1178
  existing_sandbox_id=sandbox_state['sandbox_id'],
1179
  )
1180
  if sandbox_error:
1181
  yield update_markdown_output("❌ HTML sandbox failed to run!", clear_output=True)
1182
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{sandbox_error}\n```\n\n</details>\n\n")
1183
  else:
1184
  yield update_markdown_output("✅ HTML sandbox is ready!", clear_output=True)
1185
  yield (
 
1197
  yield update_markdown_output("🔄 Setting up React sandbox...")
1198
  code_run_result = run_react_sandbox(
1199
  code=code,
1200
+ install_command=install_command,
1201
  existing_sandbox_id=sandbox_state['sandbox_id'],
1202
  )
1203
  sandbox_id, sandbox_error = code_run_result['sandbox_id'], code_run_result['stderr']
1204
  if code_run_result['is_run_success'] is False and sandbox_error:
1205
  yield update_markdown_output("❌ React sandbox failed to run!", clear_output=True)
1206
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{sandbox_error}\n```\n\n</details>\n\n")
1207
  else:
1208
  yield update_markdown_output("✅ React sandbox is ready!", clear_output=True)
1209
  yield (
 
1221
  yield update_markdown_output("🔄 Setting up Vue sandbox...")
1222
  code_run_result = run_vue_sandbox(
1223
  code=code,
1224
+ install_command=install_command,
1225
  existing_sandbox_id=sandbox_state['sandbox_id'],
1226
  )
1227
  sandbox_id, sandbox_error = code_run_result['sandbox_id'], code_run_result['stderr']
1228
  if code_run_result['is_run_success'] is False and code_run_result['stderr']:
1229
  yield update_markdown_output("❌ Vue sandbox failed to run!", clear_output=True)
1230
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{code_run_result['stderr']}\n```\n\n</details>\n\n")
1231
  else:
1232
  yield update_markdown_output("✅ Vue sandbox is ready!", clear_output=True)
1233
  yield (
 
1245
  yield update_markdown_output("🔄 Setting up PyGame sandbox...")
1246
  code_run_result = run_pygame_sandbox(
1247
  code=code,
1248
+ install_command=install_command,
1249
  existing_sandbox_id=sandbox_state['sandbox_id'],
1250
  )
1251
  sandbox_id, sandbox_error = code_run_result['sandbox_id'], code_run_result['stderr']
1252
  if code_run_result['is_run_success'] is False and code_run_result['stderr']:
1253
  yield update_markdown_output("❌ PyGame sandbox failed to run!", clear_output=True)
1254
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{code_run_result['stderr']}\n```\n\n</details>\n\n")
1255
  else:
1256
  yield update_markdown_output("✅ PyGame sandbox is ready!", clear_output=True)
1257
  yield (
 
1269
  yield update_markdown_output("🔄 Setting up Gradio sandbox...")
1270
  sandbox_url, sandbox_id, sandbox_error = run_gradio_sandbox(
1271
  code=code,
1272
+ install_command=install_command,
1273
  existing_sandbox_id=sandbox_state['sandbox_id'],
1274
  )
1275
  if sandbox_error:
1276
  yield update_markdown_output("❌ Gradio sandbox failed to run!", clear_output=True)
1277
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{sandbox_error}\n```\n\n</details>\n\n")
1278
  else:
1279
  yield update_markdown_output("✅ Gradio sandbox is ready!", clear_output=True)
1280
  yield (
 
1292
  yield update_markdown_output("🔄 Setting up Streamlit sandbox...")
1293
  sandbox_url, sandbox_id, sandbox_error = run_streamlit_sandbox(
1294
  code=code,
1295
+ install_command=install_command,
1296
  existing_sandbox_id=sandbox_state['sandbox_id'],
1297
  )
1298
  if sandbox_error:
1299
  yield update_markdown_output("❌ Streamlit sandbox failed to run!", clear_output=True)
1300
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{sandbox_error}\n```\n\n</details>\n\n")
1301
  else:
1302
  yield update_markdown_output("✅ Streamlit sandbox is ready!", clear_output=True)
1303
  yield (
 
1317
  html_code = mermaid_to_html(code, theme='light')
1318
  sandbox_url, sandbox_id, sandbox_error = run_html_sandbox(
1319
  code=html_code,
1320
+ install_command=install_command,
1321
  existing_sandbox_id=sandbox_state['sandbox_id'],
1322
  )
1323
  if sandbox_error:
1324
  yield update_markdown_output("❌ Mermaid visualization failed to render!", clear_output=True)
1325
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{sandbox_error}\n```\n\n</details>\n\n")
1326
  else:
1327
  yield update_markdown_output("✅ Mermaid visualization is ready!", clear_output=True)
1328
  yield (
 
1339
  case SandboxEnvironment.PYTHON_RUNNER:
1340
  yield update_markdown_output("🔄 Running Python Runner...", clear_output=True)
1341
  sandbox_output, sandbox_error = run_code_interpreter(
1342
+ code=code, code_language='python', install_command=install_command
1343
  )
1344
  if sandbox_error:
1345
  yield update_markdown_output("❌ Python Runner failed to run!", clear_output=True)
1346
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{sandbox_error}\n```\n\n</details>\n\n")
1347
  else:
1348
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1349
  yield (
 
1363
  )
1364
  case SandboxEnvironment.JAVASCRIPT_RUNNER:
1365
  yield update_markdown_output("🔄 Running JavaScript Runner...", clear_output=True)
1366
+ # Convert JavaScript code to HTML
1367
+ html_code = javascript_to_html(code)
1368
+ # Run the HTML in sandbox
1369
+ sandbox_url, sandbox_id, sandbox_error = run_html_sandbox(
1370
+ code=html_code, install_command=install_command, sandbox_id=sandbox_state.get('sandbox_id')
1371
  )
1372
+ # Update sandbox state with the sandbox_id
1373
+ sandbox_state['sandbox_id'] = sandbox_id
1374
  if sandbox_error:
1375
  yield update_markdown_output("❌ JavaScript Runner failed to run!", clear_output=True)
1376
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{sandbox_error}\n```\n\n</details>\n\n")
1377
  else:
1378
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1379
  yield (
1380
  gr.Markdown(
1381
+ value=markdown_output_text,
1382
  sanitize_html=False,
1383
  visible=True,
1384
  ),
1385
  SandboxComponent(
1386
+ value=(sandbox_url, True, []),
1387
+ label="JavaScript Sandbox",
1388
+ visible=True,
1389
+ key=f"js_sandbox_{int(time.time() * 1000)}",
1390
  ),
1391
  gr.skip(),
1392
  gr.skip(),
 
1398
  )
1399
  if sandbox_error:
1400
  yield update_markdown_output("❌ C Runner failed to run!", clear_output=True)
1401
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{sandbox_error}\n```\n\n</details>\n\n")
1402
  else:
1403
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1404
  yield (
 
1423
  )
1424
  if sandbox_error:
1425
  yield update_markdown_output("❌ C++ Runner failed to run!", clear_output=True)
1426
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{sandbox_error}\n```\n\n</details>\n\n")
1427
  else:
1428
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1429
  yield (
 
1448
  )
1449
  if sandbox_error:
1450
  yield update_markdown_output("❌ Java Runner failed to run!", clear_output=True)
1451
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{sandbox_error}\n```\n\n</details>\n\n")
1452
  else:
1453
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1454
  yield (
 
1473
  )
1474
  if sandbox_error:
1475
  yield update_markdown_output("❌ Go Runner failed to run!", clear_output=True)
1476
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{sandbox_error}\n```\n\n</details>\n\n")
1477
  else:
1478
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1479
  yield (
 
1508
  )
1509
  if sandbox_error:
1510
  yield update_markdown_output("❌ Rust Runner failed to run!", clear_output=True)
1511
+ yield update_markdown_output(f"<details open><summary><strong>🚨 Stderr</strong></summary>\n\n```\n{sandbox_error}\n```\n\n</details>\n\n")
1512
  else:
1513
  yield update_markdown_output("✅ Code execution is ready!", clear_output=True)
1514
  yield (
sandbox/prompts.py CHANGED
@@ -7,9 +7,9 @@ You are an expert Software Engineer, UI/UX designer, and product manager. Your t
7
  If you do a great job based on the instructions, you will be rewarded with a high salary and a promotion.
8
 
9
  Your code must be written using one of these supported development frameworks and environments:
10
- - React (JavaScript/TypeScript)
11
- - Vue (JavaScript/TypeScript)
12
- - HTML (Vanilla HTML)
13
  - Gradio (Python)
14
  - Streamlit (Python)
15
  - PyGame (Python)
@@ -56,7 +56,7 @@ For Python development, you must follow these constraints:
56
  - For any programs that require user inputs, you MUST USE `gradio` or `streamlit`
57
  - Choose suitable PyPI packages to be imported, e.g., `import pandas`
58
  - Avoid using libraries that require desktop GUI interfaces, with the exceptions of `pygame`, `gradio`, and `streamlit` which are explicitly supported
59
- - For PyGame applications, you have to write the main function as an async function like:
60
  ```python
61
  import asyncio
62
  import pygame
@@ -95,6 +95,33 @@ The code must be in the markdown format:
95
  ```<language>
96
  <code>
97
  ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  """
99
 
100
  DEFAULT_PYTHON_RUNNER_INSTRUCTION = """
@@ -125,6 +152,9 @@ Before you begin writing any code, you must follow these fundamental rules:
125
  - Your response must contain a clear explanation of the solution you are providing
126
  - ALWAYS generate complete, self-contained code in a single file
127
  - If you use any external libraries, make sure to specify them for installation with `npm install`
 
 
 
128
  - Make sure to include all necessary code in one file
129
  - Ensure the code is self-contained and does not rely on browser-specific APIs
130
 
@@ -168,6 +198,10 @@ Before you begin writing any code, you must follow these fundamental rules:
168
  - Your response must contain a clear explanation of the solution you are providing
169
  - ALWAYS generate complete, self-contained code in a single file
170
  - If you use any external libraries, make sure to specify them for installation with `npm install`
 
 
 
 
171
  - Make sure the program is functional by creating a state when needed and having no required props
172
  - Make sure it can run by itself by using a default export at the end of the file
173
  - DO NOT CALL `ReactDOM.render()` AT THE END OF THE FILE
@@ -200,6 +234,10 @@ Before you begin writing any code, you must follow these fundamental rules:
200
  - Your response must contain a clear explanation of the solution you are providing
201
  - ALWAYS generate complete, self-contained code in a single file
202
  - If you use any external libraries, make sure to specify them for installation with `npm install`
 
 
 
 
203
  - Make sure the program is functional by creating a state when needed and having no required props
204
  - The component should be a simple custom page in a styled `<div>` element
205
  - Do not include <NuxtWelcome /> or reference any external components
 
7
  If you do a great job based on the instructions, you will be rewarded with a high salary and a promotion.
8
 
9
  Your code must be written using one of these supported development frameworks and environments:
10
+ - React (JavaScript/TypeScript) -- version 18.3.1
11
+ - Vue (JavaScript/TypeScript) -- version 3.5.13
12
+ - HTML (Plain HTML)
13
  - Gradio (Python)
14
  - Streamlit (Python)
15
  - PyGame (Python)
 
56
  - For any programs that require user inputs, you MUST USE `gradio` or `streamlit`
57
  - Choose suitable PyPI packages to be imported, e.g., `import pandas`
58
  - Avoid using libraries that require desktop GUI interfaces, with the exceptions of `pygame`, `gradio`, and `streamlit` which are explicitly supported
59
+ - For PyGame applications, we use pygbag to build the application. You have to write the main function as an async function like:
60
  ```python
61
  import asyncio
62
  import pygame
 
95
  ```<language>
96
  <code>
97
  ```
98
+
99
+ YOU MUST ALWAYS PROVIDE A CODE BLOCK FOR THE CODE TO BE EXECUTED. DO NOT EXPLAIN THE CODE, JUST PROVIDE THE CODE BLOCK.
100
+
101
+ IN ADDITION TO THE PROGRAM BLOCK, YOU MUST INSTALL ALL THE COMPATIBLE DEPENDENCIES FOR THE CODE TO BE EXECUTED, USING THE FOLLOWING FORMAT:
102
+ ```bash
103
+ COMMAND TO INSTALL DEPENDENCIES GRACEFULLY WITHOUT BREAKING THE CONFLICTS
104
+ ```
105
+
106
+ FOR NPM INSTALLATIONS:
107
+ - Use `--prefer-offline --no-audit --no-fund --legacy-peer-deps` to avoid conflicts
108
+ - Use compatible package versions (e.g., react-router-dom@^6.0.0 instead of latest)
109
+ - DO NOT NEED TO INSTALL `react`, `react-dom`, and `vue` packages. They are already installed.
110
+ - Include all required peer dependencies explicitly
111
+ - For React Router, use v6+ syntax (Routes instead of Switch)
112
+ - For CSS imports, include the base package (e.g., easymde for react-simplemde-editor)
113
+ - Avoid packages requiring Node.js v20+ (sandbox has v18)
114
+
115
+ FOR PIP INSTALLATIONS:
116
+ - YOU MUST NOT INSTALL ANY DEEP LEARNING DEPENDENCIES. THE ENVIRONMENT IS CPU ONLY.
117
+ - IF THE USER SAYS TO INSTALL A PACKAGE, YOU MUST INSTALL IT.
118
+ - Use `uv pip install --system` to install packages.
119
+
120
+ YOU DONT NEED TO INSTALL ANY FOLLOWING DEPENDENCIES:
121
+ - `gradio`, `streamlit`, `pygame`, `mermaid`, `react`, `react-dom`, `vue`
122
+
123
+ THERE IS NO EXTERNAL FILE IN THE LOCAL FILE SYSTEM.
124
+ WHATEVER THE USER SAYS (e.g, "hello"), YOU MUST ALWAYS WRITE A PROGRAM TO RESPOND.
125
  """
126
 
127
  DEFAULT_PYTHON_RUNNER_INSTRUCTION = """
 
152
  - Your response must contain a clear explanation of the solution you are providing
153
  - ALWAYS generate complete, self-contained code in a single file
154
  - If you use any external libraries, make sure to specify them for installation with `npm install`
155
+ - For npm installations, use compatible versions and include all peer dependencies:
156
+ - Use `--legacy-peer-deps` flag to avoid version conflicts
157
+ - Avoid packages requiring Node.js v20+ (sandbox has v18)
158
  - Make sure to include all necessary code in one file
159
  - Ensure the code is self-contained and does not rely on browser-specific APIs
160
 
 
198
  - Your response must contain a clear explanation of the solution you are providing
199
  - ALWAYS generate complete, self-contained code in a single file
200
  - If you use any external libraries, make sure to specify them for installation with `npm install`
201
+ - For npm installations, use compatible versions and include all peer dependencies:
202
+ - Use `react-router-dom@^6.0.0` (not v7+) and React Router v6+ syntax (Routes instead of Switch)
203
+ - Include base packages for CSS (e.g., `easymde` for `react-simplemde-editor`)
204
+ - Use `--legacy-peer-deps` flag to avoid version conflicts
205
  - Make sure the program is functional by creating a state when needed and having no required props
206
  - Make sure it can run by itself by using a default export at the end of the file
207
  - DO NOT CALL `ReactDOM.render()` AT THE END OF THE FILE
 
234
  - Your response must contain a clear explanation of the solution you are providing
235
  - ALWAYS generate complete, self-contained code in a single file
236
  - If you use any external libraries, make sure to specify them for installation with `npm install`
237
+ - For npm installations, use compatible versions and include all peer dependencies:
238
+ - Use `--legacy-peer-deps` flag to avoid version conflicts
239
+ - Include base packages for CSS when needed
240
+ - Avoid packages requiring Node.js v20+ (sandbox has v18)
241
  - Make sure the program is functional by creating a state when needed and having no required props
242
  - The component should be a simple custom page in a styled `<div>` element
243
  - Do not include <NuxtWelcome /> or reference any external components
sandbox/sandbox_manager.py CHANGED
@@ -20,7 +20,6 @@ def create_sandbox(template: str = SANDBOX_TEMPLATE_ID) -> Sandbox:
20
  Create a new sandbox.
21
  Will retry if the sandbox creation fails.
22
  '''
23
- print("Creating new sandbox...")
24
  for attempt in range(1, SANDBOX_RETRY_COUNT + 1):
25
  try:
26
  return Sandbox(
@@ -90,13 +89,6 @@ def run_command_in_sandbox(
90
  stderrs.append(str(e))
91
  is_run_success = False
92
 
93
- if print_output:
94
- print(f"Command: {command}")
95
- for stdout in stdouts:
96
- print(stdout)
97
- for stderr in stderrs:
98
- print(stderr)
99
-
100
  return is_run_success, stdouts, stderrs
101
 
102
 
@@ -116,8 +108,6 @@ def install_pip_dependencies(sandbox: Sandbox, dependencies: list[str]) -> list[
116
  sandbox.commands.run(
117
  f"uv pip install --system {dependency}",
118
  timeout=60 * 3,
119
- on_stdout=lambda message: print(message),
120
- on_stderr=lambda message: print(message),
121
  )
122
  except Exception as e:
123
  install_errors.append(f"Error during installing pip package {dependency}: {str(e)}")
@@ -178,8 +168,6 @@ def install_npm_dependencies(sandbox: Sandbox, dependencies: list[str], project_
178
  f"npm install {dependency} --prefer-offline --no-audit --no-fund --legacy-peer-deps",
179
  cwd=project_root,
180
  timeout=60 * 3,
181
- on_stdout=lambda message: print(message),
182
- on_stderr=lambda message: print(message),
183
  )
184
  except Exception as e:
185
  install_errors.append(f"Error during installing npm package {dependency}:" + str(e))
 
20
  Create a new sandbox.
21
  Will retry if the sandbox creation fails.
22
  '''
 
23
  for attempt in range(1, SANDBOX_RETRY_COUNT + 1):
24
  try:
25
  return Sandbox(
 
89
  stderrs.append(str(e))
90
  is_run_success = False
91
 
 
 
 
 
 
 
 
92
  return is_run_success, stdouts, stderrs
93
 
94
 
 
108
  sandbox.commands.run(
109
  f"uv pip install --system {dependency}",
110
  timeout=60 * 3,
 
 
111
  )
112
  except Exception as e:
113
  install_errors.append(f"Error during installing pip package {dependency}: {str(e)}")
 
168
  f"npm install {dependency} --prefer-offline --no-audit --no-fund --legacy-peer-deps",
169
  cwd=project_root,
170
  timeout=60 * 3,
 
 
171
  )
172
  except Exception as e:
173
  install_errors.append(f"Error during installing npm package {dependency}:" + str(e))