Improve workspace

This commit is contained in:
Dita Aji Pratama 2026-10-03 21:31:07 +07:00
parent 8c8237aec4
commit e5e40281af
6 changed files with 70 additions and 61 deletions

View File

@ -2,9 +2,9 @@ import os, sys, threading, time, signal
import config
from lib import gadget, personality, moop, ragroleplay as ragroleplay_lib
from lib import gadget, personality, moop, workspace, ragroleplay as ragroleplay_lib
from modules import argsparser
from tools import coder, carrack, ragroleplay as ragroleplay_tools, vision, imagegen, smart, smart_rp
from tools import coder, carrack, ragroleplay as ragroleplay_tools, vision, imagegen, smart, smart_rp, syshendrik
from services.llm_client import LLMClient
from services.xmpp_client import XMPPClient
@ -20,7 +20,6 @@ tools_definition = [
gadget.tools_mapping( schema = coder.schema_run_bash, handler = coder.run_bash ),
gadget.tools_mapping( schema = coder.schema_search_code, handler = coder.search_code ),
gadget.tools_mapping( schema = coder.schema_git_operation, handler = coder.git_operation ),
gadget.tools_mapping( schema = coder.schema_workspace_change, handler = coder.workspace_change ),
gadget.tools_mapping( schema = coder.schema_search_grep, handler = coder.search_grep ),
gadget.tools_mapping( schema = coder.schema_search_glob, handler = coder.search_glob ),
# Carrack Tools
@ -47,6 +46,8 @@ tools_definition = [
gadget.tools_mapping( schema = ragroleplay_tools.schema_memories_delete, handler = ragroleplay_tools.memories_delete ),
gadget.tools_mapping( schema = ragroleplay_tools.schema_end_session, handler = ragroleplay_tools.end_session ),
# SysHendrik Tools
gadget.tools_mapping( schema = syshendrik.schema_workspace_change, handler = syshendrik.workspace_change ),
]
@ -67,7 +68,7 @@ def main():
if not os.path.isdir(resolved):
print(f"Error: '{resolved}' is not a valid directory", flush=True)
sys.exit(1)
coder.set_current_workspace(resolved)
workspace.set_current_workspace(resolved)
# Inference
llm_client = LLMClient("", "", "", config.llm_timeout)

View File

@ -9,7 +9,7 @@ import curses
import os
import config
from .agent import log
from tools.coder import set_current_workspace
from lib import workspace
from . import keycodes
from .moopui import (
model_selector_popup,
@ -157,7 +157,7 @@ def workspace_popup(app, stdscr):
if ws:
resolved = os.path.abspath(ws)
if os.path.isdir(resolved):
set_current_workspace(resolved)
workspace.set_current_workspace(resolved)
log(app, "system", f"Workspace \u2192 {resolved}")
else:
log(app, "error", f"Invalid directory: {resolved}")

View File

@ -6,7 +6,7 @@
import curses
import json
from tools.coder import get_current_workspace
from lib import workspace
from . import theme
from .actions import ACTIONS
@ -361,7 +361,7 @@ def draw_status(app, stdscr):
mode = " PROCESSING " if app.processing else " READY "
set_name = (getattr(app, "model_set_name", "") or "-").strip() or "-"
model = (app.llm.model or "-").strip() or "-"
ws = get_current_workspace() or "-"
ws = workspace.get_current_workspace() or "-"
send_key = ACTIONS["send_prompt"].get("shortcut") or "Ctrl+Return"
right = f" {app.character_name} {send_key}:Send "

View File

@ -4,18 +4,7 @@ import re
import fnmatch
import glob as glob_module
# Global state to track the agent's current working directory
# This ensures that subsequent bash commands run in the correct directory
CURRENT_WORKSPACE = os.getcwd()
def get_current_workspace():
global CURRENT_WORKSPACE
return CURRENT_WORKSPACE
def set_current_workspace(path):
global CURRENT_WORKSPACE
CURRENT_WORKSPACE = path
os.chdir(path)
from lib import workspace
schema_read_file = {
"type": "function",
@ -34,8 +23,8 @@ schema_read_file = {
def read_file(path):
try:
# Use absolute path if it's relative to CURRENT_WORKSPACE
full_path = os.path.join(get_current_workspace(), path) if not os.path.isabs(path) else path
# Use absolute path if it's relative to current workspace
full_path = os.path.join(workspace.get_current_workspace(), path) if not os.path.isabs(path) else path
with open(full_path, 'r', encoding='utf-8', errors='replace') as f:
lines = f.readlines()
return ''.join(f"{i+1}: {line}" for i, line in enumerate(lines))
@ -60,7 +49,7 @@ schema_write_file = {
def write_file(path, content):
try:
full_path = os.path.join(get_current_workspace(), path) if not os.path.isabs(path) else path
full_path = os.path.join(workspace.get_current_workspace(), path) if not os.path.isabs(path) else path
with open(full_path, 'w', encoding='utf-8') as f:
f.write(content)
return f"Successfully wrote to {full_path}"
@ -86,7 +75,7 @@ schema_edit_file = {
def edit_file(path, old_string, new_string):
try:
full_path = os.path.join(get_current_workspace(), path) if not os.path.isabs(path) else path
full_path = os.path.join(workspace.get_current_workspace(), path) if not os.path.isabs(path) else path
with open(full_path, 'r', encoding='utf-8', errors='replace') as f:
content = f.read()
if old_string not in content:
@ -116,7 +105,7 @@ schema_run_bash = {
def run_bash(command):
try:
# Prepend 'cd' to the command to ensure it runs in the correct workspace
full_command = f"cd '{get_current_workspace()}' && {command}"
full_command = f"cd '{workspace.get_current_workspace()}' && {command}"
result = subprocess.run(full_command, shell=True, capture_output=True, text=True, timeout=30)
return f"stdout:\n{result.stdout}\nstderr:\n{result.stderr}\nreturn code: {result.returncode}"
except Exception as e:
@ -142,7 +131,7 @@ schema_search_code = {
def search_code(pattern, search_type, path="."):
try:
# Resolve path relative to workspace
search_path = os.path.join(get_current_workspace(), path) if not os.path.isabs(path) else path
search_path = os.path.join(workspace.get_current_workspace(), path) if not os.path.isabs(path) else path
if search_type == "glob":
files = glob_module.glob(f"{search_path}/**/{pattern}", recursive=True)
@ -187,41 +176,11 @@ def git_operation(args):
try:
# Execute git command from the current workspace
full_command = ["git", *args]
result = subprocess.run(full_command, cwd=get_current_workspace(), capture_output=True, text=True, timeout=10)
result = subprocess.run(full_command, cwd=workspace.get_current_workspace(), capture_output=True, text=True, timeout=10)
return f"stdout:\n{result.stdout}\nstderr:\n{result.stderr}\nreturn code: {result.returncode}"
except Exception as e:
return f"Error running git command: {str(e)}"
schema_workspace_change = {
"type": "function",
"function": {
"name": "workspace_change",
"description": "Change the current working directory of the agent session. Supports tilde (~) expansion for the user home directory (/home/aji/).",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "The target directory path to change to."}
},
"required": ["path"]
}
}
}
def workspace_change(path):
try:
if path.startswith("~"):
target_path = os.path.expanduser(path)
else:
target_path = os.path.abspath(path)
if os.path.exists(target_path) and os.path.isdir(target_path):
set_current_workspace(target_path)
return f"Successfully changed workspace to: {target_path}"
else:
return f"Error: The path {target_path} does not exist or is not a directory."
except Exception as e:
return f"Error changing workspace: {str(e)}"
schema_search_grep = {
"type": "function",
"function": {
@ -241,7 +200,7 @@ schema_search_grep = {
def search_grep(pattern, path=".", include=None):
try:
search_path = os.path.join(get_current_workspace(), path) if not os.path.isabs(path) else path
search_path = os.path.join(workspace.get_current_workspace(), path) if not os.path.isabs(path) else path
results = []
for root, dirs, files in os.walk(search_path):
for file in files:
@ -277,7 +236,7 @@ schema_search_glob = {
def search_glob(pattern, path="."):
try:
search_path = os.path.join(get_current_workspace(), path) if not os.path.isabs(path) else path
search_path = os.path.join(workspace.get_current_workspace(), path) if not os.path.isabs(path) else path
files = glob_module.glob(f"{search_path}/{pattern}", recursive=True)
def _isfile(f):
try:

49
tools/syshendrik.py Normal file
View File

@ -0,0 +1,49 @@
import os
from lib import workspace
# Tools untuk membantu sistem Hendrik.
# State workspace sesi dimiliki lib.workspace dan dipakai bersama oleh
# tool coding, vision, dan TUI -- di sini hanya dibungkus sebagai tool aksi.
schema_workspace_change = {
"type": "function",
"function": {
"name": "workspace_change",
"description": "Change the current working directory of the agent session. Supports tilde (~) expansion for the user home directory (/home/aji/).",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "The target directory path to change to."}
},
"required": ["path"]
}
}
}
def workspace_change(path):
previous_path = workspace.get_current_workspace()
try:
if path.startswith("~"):
target_path = os.path.expanduser(path)
else:
target_path = os.path.abspath(path)
if os.path.exists(target_path) and os.path.isdir(target_path):
workspace.set_current_workspace(target_path)
return (
f"Successfully changed workspace.\n"
f"previous workspace: {previous_path}\n"
f"current workspace : {target_path}"
)
else:
return (
f"Error: The path {target_path} does not exist or is not a directory.\n"
f"previous workspace: {previous_path}\n"
f"current workspace : {previous_path} (unchanged)"
)
except Exception as e:
return (
f"Error changing workspace: {str(e)}\n"
f"previous workspace: {previous_path}\n"
f"current workspace : {workspace.get_current_workspace()}"
)

View File

@ -6,7 +6,7 @@ import tempfile
import urllib.request
import ftplib
from urllib.parse import urlparse
from tools.coder import get_current_workspace
from lib import workspace
MIME_MAP = {
".jpg": "image/jpeg",
@ -152,7 +152,7 @@ def describe_image(path):
return f"Error fetching SFTP: {e}"
# ── Local file ─────────────────────────────────────────────────────
full_path = os.path.join(get_current_workspace(), path) if not os.path.isabs(path) else path
full_path = os.path.join(workspace.get_current_workspace(), path) if not os.path.isabs(path) else path
if not os.path.isfile(full_path):
return f"Error: file not found: {full_path}"