From f5ea2445ae08ec72b81c9b5316ffe3e1c998c179 Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Thu, 28 Aug 2025 19:59:44 +0100 Subject: [PATCH 1/9] bug fix --- codetide/agents/tide/agent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codetide/agents/tide/agent.py b/codetide/agents/tide/agent.py index a30afe8..4dd1bea 100644 --- a/codetide/agents/tide/agent.py +++ b/codetide/agents/tide/agent.py @@ -220,7 +220,7 @@ def commit(self, message :str): """ try: # Open the repository - repo = self.repo + repo = self.tide.repo # Get author and committer information config = repo.config From 992d189adbf4c90221380b1c783933db3e9b69a3 Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Thu, 28 Aug 2025 20:21:01 +0100 Subject: [PATCH 2/9] added placeholder for bytes files --- codetide/core/defaults.py | 2 ++ codetide/parsers/generic_parser.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/codetide/core/defaults.py b/codetide/core/defaults.py index 49bc901..9e4b7ca 100644 --- a/codetide/core/defaults.py +++ b/codetide/core/defaults.py @@ -89,6 +89,8 @@ BREAKLINE = "\n" +DEFAULT_BYTES_CONTENT_PLACEHOLDERS = "< suppressed bytes content >" + CODETIDE_ASCII_ART = """ ███████╗ ██████╗ ██████╗ ███████╗████████╗██╗██████╗ ███████╗ diff --git a/codetide/parsers/generic_parser.py b/codetide/parsers/generic_parser.py index 6a75aec..480da08 100644 --- a/codetide/parsers/generic_parser.py +++ b/codetide/parsers/generic_parser.py @@ -1,4 +1,5 @@ from ..core.models import CodeBase, CodeFileModel, ImportStatement +from ..core.defaults import DEFAULT_BYTES_CONTENT_PLACEHOLDERS from ..parsers.base_parser import BaseParser from ..core.common import readFile @@ -57,7 +58,7 @@ async def parse_file(self, file_path: Union[str, Path], root_path: Optional[Unio def parse_code(self, file_path :Path, code :str): codeFile = CodeFileModel( file_path=str(file_path), - raw=code + raw=code if not isinstance(code, bytes) else DEFAULT_BYTES_CONTENT_PLACEHOLDERS ) return codeFile From 1e5e06365227987f4d79c42b34b56d05225b4101 Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Thu, 28 Aug 2025 22:28:43 +0100 Subject: [PATCH 3/9] fixed checkout commit push on hf_demo --- examples/hf_demo_space/app.py | 9 +++---- examples/hf_demo_space/git_utils.py | 39 +++++++++++++---------------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/examples/hf_demo_space/app.py b/examples/hf_demo_space/app.py index 4993f8f..524f78a 100644 --- a/examples/hf_demo_space/app.py +++ b/examples/hf_demo_space/app.py @@ -18,7 +18,7 @@ from aicore.llm import Llm, LlmConfig from aicore.config import Config -from git_utils import push_new_branch, validate_git_url, checkout_new_branch +from git_utils import commit_and_push_changes, validate_git_url, checkout_new_branch from chainlit.cli import run_chainlit from typing import Optional from pathlib import Path @@ -260,10 +260,9 @@ async def on_stop_steps(action :cl.Action): @cl.action_callback("checkout_commit_push") async def on_checkout_commit_push(action :cl.Action): agent_tide_ui: AgentTideUi = cl.user_session.get("AgentTideUi") - await agent_tide_ui.agent_tide.prepare_commit() - agent_tide_ui.agent_tide.commit("AgentTide - add all and push") - - push_new_branch(agent_tide_ui.agent_tide.tide.repo, branch_name=cl.user_session.get("current_branch_name")) + # await agent_tide_ui.agent_tide.prepare_commit() + # agent_tide_ui.agent_tide.commit("AgentTide - add all and push") + await commit_and_push_changes(agent_tide_ui.agent_tide.tide.rootpath, branch_name=cl.user_session.get("current_branch_name"), commit_message="AgentTide - add all and push", checkout=False) @cl.action_callback("inspect_code_context") async def on_inspect_context(action :cl.Action): diff --git a/examples/hf_demo_space/git_utils.py b/examples/hf_demo_space/git_utils.py index 0ad4686..b9b12fc 100644 --- a/examples/hf_demo_space/git_utils.py +++ b/examples/hf_demo_space/git_utils.py @@ -41,7 +41,7 @@ async def validate_git_url(url) -> None: except subprocess.CalledProcessError as e: raise ValueError(f"Invalid Git repository URL: {url}. Error: {e.stderr}") from e -async def commit_and_push_changes(repo_path: Path, branch_name: str = None, commit_message: str = "Auto-commit: Save changes") -> None: +async def commit_and_push_changes(repo_path: Path, branch_name: str = None, commit_message: str = "Auto-commit: Save changes", checkout :bool=True) -> None: """Add all changes, commit with default message, and push to remote.""" repo_path_str = str(repo_path) @@ -51,27 +51,26 @@ async def commit_and_push_changes(repo_path: Path, branch_name: str = None, comm if not branch_name: branch_name = f"agent-tide-{ulid()}" - # Create and checkout new branch - process = await asyncio.create_subprocess_exec( - "git", "checkout", "-b", branch_name, - cwd=repo_path_str, - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE, - text=True - ) - - stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=10) - - if process.returncode != 0: - raise subprocess.CalledProcessError(process.returncode, ["git", "checkout", "-b", branch_name], stdout, stderr) - + if checkout: + # Create and checkout new branch + process = await asyncio.create_subprocess_exec( + "git", "checkout", "-b", branch_name, + cwd=repo_path_str, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) + + stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=10) + + if process.returncode != 0: + raise subprocess.CalledProcessError(process.returncode, ["git", "checkout", "-b", branch_name], stdout, stderr) + # Add all changes process = await asyncio.create_subprocess_exec( "git", "add", ".", cwd=repo_path_str, stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE, - text=True + stderr=asyncio.subprocess.PIPE ) stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=30) @@ -84,8 +83,7 @@ async def commit_and_push_changes(repo_path: Path, branch_name: str = None, comm "git", "commit", "-m", commit_message, cwd=repo_path_str, stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE, - text=True + stderr=asyncio.subprocess.PIPE ) stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=30) @@ -101,8 +99,7 @@ async def commit_and_push_changes(repo_path: Path, branch_name: str = None, comm "git", "push", "origin", branch_name, cwd=repo_path_str, stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE, - text=True + stderr=asyncio.subprocess.PIPE ) stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=60) From b3cec0a4ecfc86d03a2d0a6f418efc291d9f4a8f Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Thu, 28 Aug 2025 22:52:59 +0100 Subject: [PATCH 4/9] fixed commits --- codetide/agents/tide/agent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codetide/agents/tide/agent.py b/codetide/agents/tide/agent.py index 4dd1bea..9cbccea 100644 --- a/codetide/agents/tide/agent.py +++ b/codetide/agents/tide/agent.py @@ -224,8 +224,8 @@ def commit(self, message :str): # Get author and committer information config = repo.config - author_name = config.get('user.name', 'Unknown Author') - author_email = config.get('user.email', 'unknown@example.com') + author_name = config._get('user.name')[1].value or 'Unknown Author' + author_email = config._get('user.email')[1].value or 'unknown@example.com' author = pygit2.Signature(author_name, author_email) committer = author # Typically same as author From 20a51fa72670bbf0a61cde5fbb011978ca091ab8 Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Thu, 28 Aug 2025 23:16:27 +0100 Subject: [PATCH 5/9] made patches storage dir absolute --- codetide/agents/tide/agent.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/codetide/agents/tide/agent.py b/codetide/agents/tide/agent.py index 9cbccea..c6621cd 100644 --- a/codetide/agents/tide/agent.py +++ b/codetide/agents/tide/agent.py @@ -62,7 +62,7 @@ def pass_custom_logger_fn(self)->Self: def approve(self): self._has_patch = False if os.path.exists(self.patch_path): - changed_paths = process_patch(self.patch_path, open_file, write_file, remove_file, file_exists) + changed_paths = process_patch(self.patch_path, open_file, write_file, remove_file, file_exists, root_path=self.tide.rootpath) self.changed_paths.extend(changed_paths) previous_response = self.history[-1] @@ -81,10 +81,10 @@ def reject(self, feedback :str): @property def patch_path(self)->Path: - if not os.path.exists(DEFAULT_STORAGE_PATH): - os.makedirs(DEFAULT_STORAGE_PATH, exist_ok=True) + if not os.path.exists(self.tide.rootpath / DEFAULT_STORAGE_PATH): + os.makedirs(self.tide.rootpath / DEFAULT_STORAGE_PATH, exist_ok=True) - return DEFAULT_STORAGE_PATH / f"{self.session_id}.bash" + return self.tide.rootpath / DEFAULT_STORAGE_PATH / f"{self.session_id}.bash" @staticmethod def trim_messages(messages, tokenizer_fn, max_tokens :Optional[int]=None): From 030318ca861d4e65c992ab5174e11278f127acc4 Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Thu, 28 Aug 2025 23:16:56 +0100 Subject: [PATCH 6/9] ensured model_validation with logger_fn after re init --- examples/hf_demo_space/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/hf_demo_space/app.py b/examples/hf_demo_space/app.py index 524f78a..788dc24 100644 --- a/examples/hf_demo_space/app.py +++ b/examples/hf_demo_space/app.py @@ -153,6 +153,7 @@ async def start_chatr(): agent_tide_ui.agent_tide.llm = Llm.from_config(config.llm) agent_tide_ui.agent_tide.llm.provider.session_id = agent_tide_ui.agent_tide.session_id + agent_tide_ui.agent_tide.pass_custom_logger_fn() session_dir_path = DEFAULT_SESSIONS_WORKSPACE / session_id if not os.path.exists(session_dir_path): From 515469a1c1b426940ba971a5ac4fe81067100ed5 Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Thu, 28 Aug 2025 23:17:31 +0100 Subject: [PATCH 7/9] updated process_patch to receive absolute root path --- codetide/mcp/tools/patch_code/__init__.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/codetide/mcp/tools/patch_code/__init__.py b/codetide/mcp/tools/patch_code/__init__.py index 59f96b4..b933065 100644 --- a/codetide/mcp/tools/patch_code/__init__.py +++ b/codetide/mcp/tools/patch_code/__init__.py @@ -3,7 +3,7 @@ from .parser import Parser, patch_to_commit # from ....core.common import writeFile -from typing import Dict, Tuple, List, Callable +from typing import Dict, Optional, Tuple, List, Callable, Union import pathlib import os @@ -108,18 +108,24 @@ def process_patch( open_fn: Callable[[str], str], write_fn: Callable[[str, str], None], remove_fn: Callable[[str], None], - exists_fn: Callable[[str], bool] + exists_fn: Callable[[str], bool], + root_path: Optional[Union[str, pathlib.Path]]=None ) -> List[str]: """The main entrypoint function to process a patch from text to filesystem.""" if not os.path.exists(patch_path): raise DiffError("Patch path {patch_path} does not exist.") + if root_path is not None: + root_path = pathlib.Path(root_path) + # Normalize line endings before processing text = open_fn(patch_path) # FIX: Check for existence of files to be added before parsing. paths_to_add = identify_files_added(text) for p in paths_to_add: + if root_path is not None: + p = str(root_path / p) if exists_fn(p): raise DiffError(f"Add File Error - file already exists: {p}") @@ -128,6 +134,8 @@ def process_patch( # Load files with normalized line endings orig_files = {} for path in paths_needed: + if root_path is not None: + path = str(root_path / path) orig_files[path] = open_fn(path) patch, _fuzz = text_to_patch(text, orig_files) From 53ada5a483e21dbb5b744a8ac4f18f8d5c71c903 Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Thu, 28 Aug 2025 23:20:41 +0100 Subject: [PATCH 8/9] added CMD_TRIGGER_PLANNING_STEPS --- codetide/agents/tide/prompts.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codetide/agents/tide/prompts.py b/codetide/agents/tide/prompts.py index 68945e4..b44d7ac 100644 --- a/codetide/agents/tide/prompts.py +++ b/codetide/agents/tide/prompts.py @@ -327,7 +327,8 @@ """ CMD_TRIGGER_PLANNING_STEPS = """ - +You must operate in a multi-step planning and execution mode: first outline the plan step by step in a sequential way, then ask for my revision. +Do not start implementing the steps without my approval. """ CMD_WRITE_TESTS_PROMPT = """ From 1372c7ba5a5a70d17060064e1cefdcb17d3740b4 Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Thu, 28 Aug 2025 23:52:03 +0100 Subject: [PATCH 9/9] made code optional --- codetide/parsers/generic_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codetide/parsers/generic_parser.py b/codetide/parsers/generic_parser.py index 480da08..a1aa125 100644 --- a/codetide/parsers/generic_parser.py +++ b/codetide/parsers/generic_parser.py @@ -55,7 +55,7 @@ async def parse_file(self, file_path: Union[str, Path], root_path: Optional[Unio return codeFile - def parse_code(self, file_path :Path, code :str): + def parse_code(self, file_path :Path, code :Optional[str]=None): codeFile = CodeFileModel( file_path=str(file_path), raw=code if not isinstance(code, bytes) else DEFAULT_BYTES_CONTENT_PLACEHOLDERS