Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/assistant.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from google import genai
from google.genai import types
from src.config import MEMORY_FILE
from src.tools import all_tools


class ChatAssistant:
Expand Down Expand Up @@ -42,7 +43,9 @@ def _initialize_client(self):
def _create_chat_session(self):
"""creates a new chat session with the system prompt"""
history = self._load_history()
gen_config = types.GenerateContentConfig(system_instruction=self.system_prompt)
gen_config = types.GenerateContentConfig(
system_instruction=self.system_prompt, tools=all_tools
)
Comment on lines +46 to +48
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?

print(f"Initializing chat with {self.model_name}...")
return self.client.chats.create(
model=self.model_name, config=gen_config, history=history
Expand Down
14 changes: 10 additions & 4 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@
USER_NAME = "Ubeyidah"
EXIT_WORD_LIST = ["exit", "quit", "bye", "goodbye", "stop", "end", "quite"]
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.
"""
Comment on lines 5 to +15
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.


MEMORY_FILE = "vector_memory.json"
57 changes: 57 additions & 0 deletions src/tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import subprocess
from google.genai import types

ALLOWED_APPS = ["alacritty", "btop", "nvim", "yazi", "nautilus"]


def _run_safe_hyprctl(command_list: list):
"""Run hyprctl command safely."""
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}
except Exception as e:
print(f"[Tool Error: {str(e)}]")
return {"status": "error", "message": str(e)}


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.",
}
Comment on lines +25 to +35
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.



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"],
),
)
]
)
]
Comment on lines +38 to +57
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.