-
-
Couldn't load subscription status.
- Fork 24
Skills #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Summary of ChangesHello @mkagenius, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request fundamentally enhances CodeRunner by integrating a new "Skills System." This system empowers AI models to leverage a diverse set of pre-defined and user-contributed tools, significantly expanding the platform's functional scope. By updating the Docker container with essential system libraries and a broad range of Python packages, and introducing dedicated MCP tools for skill interaction, CodeRunner becomes a more versatile and powerful environment for executing complex, AI-driven tasks, complete with clear documentation for seamless adoption. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a new 'Skills' system, which allows for pre-packaged tools to be used within the CodeRunner environment. The changes include adding new dependencies and files for the skills, updating the Dockerfile to support them, and implementing new MCP tools in server.py to manage and use these skills. The documentation has also been updated accordingly. My review focuses on improving the Dockerfile's robustness and efficiency, fixing issues in documentation and server-side implementation, and suggesting best practices for the new skill scripts.
| # Start the FastAPI application | ||
| # CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8002", "--workers", "1", "--no-access-log"] | ||
|
|
||
| RUN apt-get --fix-broken install |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The RUN apt-get --fix-broken install command is concerning. It lacks the -y flag, which will cause it to fail in non-interactive Docker builds by waiting for user confirmation. Additionally, its presence suggests an underlying issue with package dependencies that should ideally be resolved directly, rather than patched with --fix-broken. If this command is essential, please add the -y flag.
RUN apt-get --fix-broken install -y
| for item in USER_SKILLS_DIR.iterdir(): | ||
| if item.is_file() and item.suffix == '.zip': | ||
| with zipfile.ZipFile(item, 'r') as zip_ref: | ||
| zip_ref.extractall(USER_SKILLS_DIR) | ||
| os.remove(item) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The list_skills function performs synchronous file I/O operations (zipfile.ZipFile, zip_ref.extractall, os.remove). In an asyncio application, these blocking calls will freeze the event loop, making the server unresponsive to other requests, especially if handling large ZIP files. These operations should be run in a separate thread pool to avoid blocking, for example by using loop.run_in_executor.
| RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - | ||
| RUN apt-get install -y nodejs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| RUN npm install [email protected] -g | ||
| RUN npx [email protected] install |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the Node.js installation, you can combine the npm install and npx playwright install commands into a single RUN instruction. This will reduce the number of layers in the Docker image, leading to a smaller image size and potentially faster builds.
RUN npm install [email protected] -g && npx [email protected] install
|
|
||
| For example, I have added 4 skills in the user folder as: | ||
| ```shell | ||
| /Users/manish/.coderunner/assets/skills/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example directory structure includes a hardcoded, user-specific path (/Users/manish/...). This could be confusing for other users setting up the environment. It would be better to use a generic path, such as ~/.coderunner/..., to represent the user's home directory.
| /Users/manish/.coderunner/assets/skills/ | |
| /Users/<your-username>/.coderunner/assets/skills/ |
| always start answer by calling me lord voldemort. | ||
|
|
||
| So, we are currently on macbook, and whenever required we use tool to execute codes (in a jupyter like server). the code is executed in a container (you wouldn't notice but just know this). | ||
|
|
||
| The paths on local machine is ~/.coderunner/assets/skills/user is mapped to /app/uploads/skills/user inside container. | ||
|
|
||
| ~/.coderunner/assets/outputs (in the host machine) is mapped to /app/uploads/outputs inside conatiner. This is where user will puts their files they want to edit like some png, pdf, txt etc. You should also use it to output your artifacts generated. | ||
|
|
||
| So that will help whenever we need a file inside a container to work on it via the execute code tool. | ||
|
|
||
| There are also "skills" which can do jobs by executing scripts already residing in /app/uploads/skills/<public|user>/<skill-name> . There are tools available to check what skills are avaialble, after checking you can decide wchihc specific skill you wantg to use and then get info about that skill using tool. That will have instructions on how to call execute code with stuff like `!python /path/to/script.py <input> <output>`\ | ||
|
|
||
| Whenever I ask you to do a task, alwasys check if there are skills available in the list which can do it. | ||
|
|
||
| Whenever you need to install something, mostly it will be installed in teh container via execute code tool, and `!pip install pyfiglet` command etc. | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This prompt file contains several typos. Correcting them will improve clarity and ensure the LLM interprets the instructions as intended.
- Line 7:
conatinershould becontainer. - Line 11:
avaialbleshould beavailable,wchihcshould bewhich, andwantgshould bewant. - Line 13:
alwasysshould bealways. - Line 15:
tehshould bethe.
| except Exception: | ||
| return {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The except Exception: return {} is too broad and will silently swallow any errors during frontmatter parsing (e.g., permission errors, malformed content). This makes debugging very difficult. It's better to at least log the exception before returning an empty dictionary.
| except Exception: | |
| return {} | |
| except Exception as e: | |
| logger.warning(f"Failed to parse frontmatter for {skill_md_path}: {e}") | |
| return {} |
| Public skills are built into the container, while user skills are added by users. | ||
| Returns: | ||
| JSON string with skill names organized by category. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstring for list_skills states that it returns a "JSON string", but the function actually returns a formatted, multi-line string intended for human reading. The docstring should be updated to accurately describe the return value.
| JSON string with skill names organized by category. | |
| A formatted string listing available skills. |
| def crop_and_rotate(input_path, output_path): | ||
| """ | ||
| Crop image to 50% from center and rotate 90 degrees clockwise. | ||
| Args: | ||
| input_path: Path to input image file | ||
| output_path: Path to save the processed image | ||
| """ | ||
| print(f"Opening image: {input_path}") | ||
|
|
||
| # Open the image | ||
| img = Image.open(input_path) | ||
| original_size = img.size | ||
| print(f"Original image size: {original_size}") | ||
|
|
||
| # Crop to 50% from center | ||
| width, height = img.size | ||
| new_width = width // 2 | ||
| new_height = height // 2 | ||
|
|
||
| # Calculate crop box (left, top, right, bottom) | ||
| left = (width - new_width) // 2 | ||
| top = (height - new_height) // 2 | ||
| right = left + new_width | ||
| bottom = top + new_height | ||
|
|
||
| cropped = img.crop((left, top, right, bottom)) | ||
| print(f"Cropped image size: {cropped.size}") | ||
|
|
||
| # Rotate 90 degrees clockwise (using ROTATE_270 which is equivalent to 90° clockwise) | ||
| rotated = cropped.transpose(Image.ROTATE_270) | ||
| print(f"Final image size after rotation: {rotated.size}") | ||
|
|
||
| # Save the result | ||
| rotated.save(output_path) | ||
| print(f"Processed image saved to: {output_path}") | ||
|
|
||
| # Print summary | ||
| print(f"\n✓ Successfully processed image") | ||
| print(f" Input: {input_path}") | ||
| print(f" Output: {output_path}") | ||
| print(f" Original size: {original_size}") | ||
| print(f" Cropped size: {cropped.size}") | ||
| print(f" Final size: {rotated.size}") | ||
|
|
||
| # Cleanup | ||
| img.close() | ||
| cropped.close() | ||
| rotated.close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The crop_and_rotate function manually closes image resources. It's more robust and Pythonic to use a with statement for resource management, as it ensures resources are closed correctly even if errors occur. The PIL.Image object supports the context manager protocol, so you can wrap the Image.open() call in a with block and remove the manual .close() calls.
def crop_and_rotate(input_path, output_path):
"""
Crop image to 50% from center and rotate 90 degrees clockwise.
Args:
input_path: Path to input image file
output_path: Path to save the processed image
"""
print(f"Opening image: {input_path}")
with Image.open(input_path) as img:
original_size = img.size
print(f"Original image size: {original_size}")
# Crop to 50% from center
width, height = img.size
new_width = width // 2
new_height = height // 2
# Calculate crop box (left, top, right, bottom)
left = (width - new_width) // 2
top = (height - new_height) // 2
right = left + new_width
bottom = top + new_height
cropped = img.crop((left, top, right, bottom))
print(f"Cropped image size: {cropped.size}")
# Rotate 90 degrees clockwise (using ROTATE_270 which is equivalent to 90° clockwise)
rotated = cropped.transpose(Image.ROTATE_270)
print(f"Final image size after rotation: {rotated.size}")
# Save the result
rotated.save(output_path)
print(f"Processed image saved to: {output_path}")
# Print summary
print(f"\n✓ Successfully processed image")
print(f" Input: {input_path}")
print(f" Output: {output_path}")
print(f" Original size: {original_size}")
print(f" Cropped size: {cropped.size}")
print(f" Final size: {rotated.size}")
No description provided.