Skip to content

Conversation

@ubeyidah
Copy link
Owner

@ubeyidah ubeyidah commented Nov 9, 2025

Tools

  • hyprland safe exec
  • application open

Summary by CodeRabbit

  • New Features
    • Assistant can now open applications on your system when requested
    • Supported applications include terminal, system monitor, text editor, file manager, and file viewer
    • All application requests are processed with built-in safety controls and access restrictions

@coderabbitai
Copy link

coderabbitai bot commented Nov 9, 2025

Walkthrough

This PR introduces tool support to the AI assistant by implementing a controlled application-launching capability. It adds a tools module with safe subprocess-based hyprctl execution, updates the system prompt to document the new tool, and integrates tool metadata into the assistant's chat configuration.

Changes

Cohort / File(s) Summary
Tool Implementation
src/tools.py
New file adding a safety wrapper for hyprctl commands, a public function to launch allowed applications with input validation, an allow-list constant (["alacritty", "btop", "nvim", "yazi", "nautilus"]), and all_tools list exposing tool metadata for the AI framework.
Configuration Update
src/config.py
Expanded SYSTEM_PROMPT constant from a brief persona to a detailed prompt that references OS context (Arch Linux/Hyprland), documents the tool_open_application(app_name) tool, provides usage guidance, and instructs the assistant to relay results in a calm tone.
Assistant Integration
src/assistant.py
Added import of all_tools from src.tools and updated GenerateContentConfig in _create_chat_session to include tools=all_tools parameter.

Sequence Diagram

sequenceDiagram
    participant User
    participant Assistant
    participant ToolSystem
    participant Hyprctl
    
    User->>Assistant: Request to open app (e.g., "open kitty")
    activate Assistant
    Assistant->>ToolSystem: Invoke tool_open_applications("kitty")
    activate ToolSystem
    ToolSystem->>ToolSystem: Validate against ALLOWED_APPS
    alt App Allowed
        ToolSystem->>Hyprctl: _run_safe_hyprctl(["dispatch", "exec", "kitty"])
        activate Hyprctl
        Hyprctl-->>ToolSystem: {status: "success", output: "..."}
        deactivate Hyprctl
        ToolSystem-->>Assistant: {status: "success", output: "..."}
    else App Blocked
        ToolSystem-->>Assistant: {status: "error", error: "App not allowed"}
    end
    deactivate ToolSystem
    Assistant->>User: Relay result in calm tone
    deactivate Assistant
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • src/tools.py: Review subprocess execution safety, allow-list completeness, and error handling in _run_safe_hyprctl() and tool_open_applications()
  • src/config.py: Verify prompt text accuracy and formatting
  • src/assistant.py: Confirm import and config integration are correct

Poem

🐰 A toolbox springs to life, so neat,
With hyprctl's dance and apps to meet,
The assistant now can open wide,
Kitty, nvim—let apps reside,
Safely gated, calm and fleet! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: hyprland app open tool created' accurately describes the main change—adding a tool to safely open applications via Hyprland's hyprctl command.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ubeyidah/ubeyida-14-feattools-add-safe-tool-to-open-applications

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/assistant.py (1)

28-28: Fix the parameter typo.

Line 28 has slef instead of self, which will cause an AttributeError when this method is called during initialization.

Apply this diff:

-    def _load_api_key(slef):
+    def _load_api_key(self):
         """Loads the api key from .env"""
🧹 Nitpick comments (1)
src/tools.py (1)

7-22: Consider parsing the JSON output and validating inputs.

The function uses the -j flag but returns raw stdout without parsing. Consider returning parsed JSON for structured access. Additionally, validate that command_list is non-empty before constructing the command to prevent silent failures.

Example refactor:

 def _run_safe_hyprctl(command_list: list):
     """Run hyprctl command safely."""
+    if not command_list:
+        return {"status": "error", "message": "command_list cannot be empty"}
+    
     try:
         full_command = ["hyprctl", "-j"] + command_list
         result = subprocess.run(
             full_command,
             capture_output=True,
             text=True,
             check=True,
             encoding="utf-8",
         )
         print(f"[Tool Executed: hyprctl -j {' '.join(command_list)}]")
-        return {"status": "success", "output": result.stdout}
+        try:
+            import json
+            parsed_output = json.loads(result.stdout)
+            return {"status": "success", "output": parsed_output}
+        except json.JSONDecodeError:
+            return {"status": "success", "output": result.stdout}
     except Exception as e:
         print(f"[Tool Error: {str(e)}]")
         return {"status": "error", "message": str(e)}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6708e83 and 9cb06b1.

📒 Files selected for processing (3)
  • src/assistant.py (2 hunks)
  • src/config.py (1 hunks)
  • src/tools.py (1 hunks)
🔇 Additional comments (2)
src/tools.py (1)

1-4: Imports and allow-list look good.

The imports are appropriate, and the ALLOWED_APPS constant provides a security boundary. However, note that the examples in SYSTEM_PROMPT ('kitty', 'firefox') don't match this list—see the comment on src/config.py.

src/assistant.py (1)

8-8: LGTM!

The import correctly brings in the tool definitions for integration with the chat session.

Comment on lines +46 to +48
gen_config = types.GenerateContentConfig(
system_instruction=self.system_prompt, tools=all_tools
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Tool execution logic is missing.

While the tools parameter is correctly added to the config, the code doesn't handle tool calls from the model. When Gemini decides to use tool_open_applications, it will return a FunctionCall in the response, which needs to be:

  1. Detected in the response
  2. Executed by calling the actual Python function
  3. Sent back to the model with send_message containing the tool result

The current send_message_stream method only handles text responses.

Do you want me to generate the tool execution logic or open an issue to track this implementation?

Comment on lines 5 to +15
SYSTEM_PROMPT = f"""
You are {ASSISTANT_NAME}, a helpful and friendly AI assistant.
You are speaking to your creator, {USER_NAME}.
Be calm, thoughtful, and slightly encouraging.
"""
You are {ASSISTANT_NAME}, a helpful AI assistant for your creator, {USER_NAME}.
You are running on Arch Linux with the Hyprland window manager.

You have one tool: `tool_open_application(app_name)`.
Use this tool to open applications like 'kitty' or 'firefox' when asked.

You MUST use this tool to fulfill any requests related to opening apps.
When the tool is used, you will get a JSON response. Relay the key information
(e.g., "OK, I've opened kitty") to {USER_NAME} in a natural, calm tone.
"""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix function name and update examples to match ALLOWED_APPS.

Two critical issues in the SYSTEM_PROMPT:

  1. Function name mismatch: Line 9 references tool_open_application (singular), but the actual function in src/tools.py is tool_open_applications (plural).

  2. Example apps not in allow-list: Line 10 mentions 'kitty' and 'firefox' as examples, but these are NOT in the ALLOWED_APPS list. The actual allowed apps are: alacritty, btop, nvim, yazi, nautilus. This will confuse the model and cause failures when it tries to use the examples.

Apply this diff:

 SYSTEM_PROMPT = f"""
 You are {ASSISTANT_NAME}, a helpful AI assistant for your creator, {USER_NAME}.
 You are running on Arch Linux with the Hyprland window manager.
 
-You have one tool: `tool_open_application(app_name)`.
-Use this tool to open applications like 'kitty' or 'firefox' when asked.
+You have one tool: `tool_open_applications(app_name)`.
+Use this tool to open applications like 'alacritty', 'btop', 'nvim', 'yazi', or 'nautilus' when asked.
 
 You MUST use this tool to fulfill any requests related to opening apps.
 When the tool is used, you will get a JSON response. Relay the key information
-(e.g., "OK, I've opened kitty") to {USER_NAME} in a natural, calm tone.
+(e.g., "OK, I've opened alacritty") to {USER_NAME} in a natural, calm tone.
 """
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
SYSTEM_PROMPT = f"""
You are {ASSISTANT_NAME}, a helpful and friendly AI assistant.
You are speaking to your creator, {USER_NAME}.
Be calm, thoughtful, and slightly encouraging.
"""
You are {ASSISTANT_NAME}, a helpful AI assistant for your creator, {USER_NAME}.
You are running on Arch Linux with the Hyprland window manager.
You have one tool: `tool_open_application(app_name)`.
Use this tool to open applications like 'kitty' or 'firefox' when asked.
You MUST use this tool to fulfill any requests related to opening apps.
When the tool is used, you will get a JSON response. Relay the key information
(e.g., "OK, I've opened kitty") to {USER_NAME} in a natural, calm tone.
"""
SYSTEM_PROMPT = f"""
You are {ASSISTANT_NAME}, a helpful AI assistant for your creator, {USER_NAME}.
You are running on Arch Linux with the Hyprland window manager.
You have one tool: `tool_open_applications(app_name)`.
Use this tool to open applications like 'alacritty', 'btop', 'nvim', 'yazi', or 'nautilus' when asked.
You MUST use this tool to fulfill any requests related to opening apps.
When the tool is used, you will get a JSON response. Relay the key information
(e.g., "OK, I've opened alacritty") to {USER_NAME} in a natural, calm tone.
"""
🤖 Prompt for AI Agents
In src/config.py around lines 5 to 15, update the SYSTEM_PROMPT to reference the
correct tool function name and use allowed app examples: change any occurrence
of "tool_open_application" to "tool_open_applications" and replace example apps
('kitty', 'firefox') with apps from ALLOWED_APPS (e.g., 'alacritty', 'btop',
'nvim', 'yazi', 'nautilus') so the prompt matches the actual function and
approved app list.

Comment on lines +25 to +35
def tool_open_applications(app_name: str):
"""Open specified application if it is allowed."""
app_name_lower = app_name.lower()
if app_name_lower in ALLOWED_APPS:
return _run_safe_hyprctl(["dispatch", "exec", app_name_lower])
else:
print(f"[Tool Error: App '{app_name}' is not on allow-list]")
return {
"status": "error",
"message": f"Application '{app_name}' is not allowed.",
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add input validation for the app_name parameter.

The function doesn't validate that app_name is a non-empty string. This could lead to unexpected behavior if called with None, empty string, or non-string types.

Apply this diff:

 def tool_open_applications(app_name: str):
     """Open specified application if it is allowed."""
+    if not app_name or not isinstance(app_name, str):
+        return {
+            "status": "error",
+            "message": "app_name must be a non-empty string."
+        }
+    
     app_name_lower = app_name.lower()
     if app_name_lower in ALLOWED_APPS:
         return _run_safe_hyprctl(["dispatch", "exec", app_name_lower])
     else:
         print(f"[Tool Error: App '{app_name}' is not on allow-list]")
         return {
             "status": "error",
             "message": f"Application '{app_name}' is not allowed.",
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def tool_open_applications(app_name: str):
"""Open specified application if it is allowed."""
app_name_lower = app_name.lower()
if app_name_lower in ALLOWED_APPS:
return _run_safe_hyprctl(["dispatch", "exec", app_name_lower])
else:
print(f"[Tool Error: App '{app_name}' is not on allow-list]")
return {
"status": "error",
"message": f"Application '{app_name}' is not allowed.",
}
def tool_open_applications(app_name: str):
"""Open specified application if it is allowed."""
if not app_name or not isinstance(app_name, str):
return {
"status": "error",
"message": "app_name must be a non-empty string."
}
app_name_lower = app_name.lower()
if app_name_lower in ALLOWED_APPS:
return _run_safe_hyprctl(["dispatch", "exec", app_name_lower])
else:
print(f"[Tool Error: App '{app_name}' is not on allow-list]")
return {
"status": "error",
"message": f"Application '{app_name}' is not allowed.",
}
🤖 Prompt for AI Agents
In src/tools.py around lines 25 to 35, the function tool_open_applications lacks
input validation for app_name; add checks that app_name is an instance of str
and that app_name.strip() is non-empty before proceeding, returning the same
error dict (status: "error", message: ...) for invalid input; after validation,
normalize with app_name_lower = app_name.strip().lower() and then check
membership in ALLOWED_APPS and call _run_safe_hyprctl as before, ensuring
non-string or empty inputs don't cause unexpected behavior.

Comment on lines +38 to +57
all_tools = [
types.Tool(
function_declarations=[
types.FunctionDeclaration(
name="tool_open_applications",
description=f"Opens an application on the user's computer, e.g. {', '.join(ALLOWED_APPS)}.",
parameters=types.Schema(
type=types.Type.OBJECT,
properties={
"app_name": types.Schema(
type=types.Type.STRING,
description=f"The name of the app to open, e.g. {', '.join(ALLOWED_APPS)}",
)
},
required=["app_name"],
),
)
]
)
]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Function name mismatch with SYSTEM_PROMPT.

The tool is named tool_open_applications (plural), but src/config.py line 9 references tool_open_application (singular). This will prevent the model from using the tool correctly.

Ensure the function name matches across all references. Either update the SYSTEM_PROMPT or rename the function.

🤖 Prompt for AI Agents
In src/tools.py around lines 38 to 57 the declared function name is
"tool_open_applications" (plural) but src/config.py line 9 references
"tool_open_application" (singular), causing a mismatch; rename the
FunctionDeclaration's name value to "tool_open_application" so it matches the
SYSTEM_PROMPT, and search the repo for any other references to
"tool_open_applications" to update them accordingly (or conversely update the
SYSTEM_PROMPT if you prefer the plural form) ensuring both places use the exact
same function name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants