Skip to content

Commit d4957c8

Browse files
committed
feat: add EditTool to main application and create integration test
1 parent c48741f commit d4957c8

2 files changed

Lines changed: 143 additions & 1 deletion

File tree

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import subprocess
2+
import time
3+
import sys
4+
import os
5+
6+
7+
def run_integration_test():
8+
print("🚀 Starting Integration Test for 'edit' tool...")
9+
10+
# Ensure current directory is in PYTHONPATH for the subprocess
11+
env = os.environ.copy()
12+
env["PYTHONPATH"] = os.getcwd() + ":" + env.get("PYTHONPATH", "")
13+
14+
# Create a test file
15+
test_filename = "test_edit_integration.txt"
16+
with open(test_filename, "w") as f:
17+
f.write("Line 1\nLine 2\nLine 3\n")
18+
19+
# Start the mini-copilot process
20+
process = subprocess.Popen(
21+
[sys.executable, "-m", "mini_copilot.main"],
22+
stdin=subprocess.PIPE,
23+
stdout=subprocess.PIPE,
24+
stderr=subprocess.STDOUT,
25+
text=True,
26+
bufsize=1,
27+
cwd=os.getcwd(),
28+
env=env,
29+
)
30+
31+
try:
32+
# 1. Wait for prompt
33+
print("Waiting for prompt...")
34+
output = ""
35+
start_time = time.time()
36+
while time.time() - start_time < 30:
37+
char = process.stdout.read(1)
38+
if not char:
39+
break
40+
output += char
41+
if "> " in output:
42+
print("✅ Prompt detected.")
43+
break
44+
45+
if "> " not in output:
46+
print(f"❌ Timed out waiting for prompt. Last output: {output}")
47+
return False
48+
49+
# 2. Trigger tool
50+
print(f"Sending message to trigger 'edit' tool on {test_filename}...")
51+
edit_request = f"Edit the file {test_filename}. Change 'Line 2' to 'Line Two'.\n"
52+
process.stdin.write(edit_request)
53+
process.stdin.flush()
54+
55+
# 3. Look for tool execution
56+
print("Monitoring for tool invocation and response...")
57+
found_tool = False
58+
found_success = False
59+
start_time = time.time()
60+
output = ""
61+
while time.time() - start_time < 60:
62+
char = process.stdout.read(1)
63+
if not char:
64+
break
65+
output += char
66+
sys.stdout.write(char)
67+
sys.stdout.flush()
68+
69+
if f"Successfully edited {test_filename}" in output:
70+
found_tool = True
71+
72+
# If the assistant replies and we found the tool message, we are good
73+
if found_tool and "> " in output:
74+
found_success = True
75+
break
76+
77+
if found_tool:
78+
# Verify file content
79+
with open(test_filename, "r") as f:
80+
content = f.read()
81+
if "Line Two" in content and "Line 2" not in content:
82+
print(f"\n✅ File content verified: {test_filename}")
83+
print("\n🎉 Integration Test PASSED!")
84+
return True
85+
else:
86+
print(f"\n❌ File content mismatch. Content: {content}")
87+
return False
88+
else:
89+
print("\n❌ Integration Test FAILED (Tool not triggered or response not found).")
90+
return False
91+
92+
finally:
93+
process.terminate()
94+
if os.path.exists(test_filename):
95+
os.remove(test_filename)
96+
97+
98+
if __name__ == "__main__":
99+
if run_integration_test():
100+
sys.exit(0)
101+
else:
102+
sys.exit(1)

mini_copilot/main.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ def completer(text, state):
2121
from mini_copilot.github_api import chat, get_copilot_token
2222
from mini_copilot.web_search import web_search
2323
from mini_copilot.exec_tool import exec_command as exec
24+
from tools.edit_tool import EditTool
2425
from mini_copilot.commands.auth import handle_login_command
2526
from mini_copilot.commands.model import handle_model_command
2627
from mini_copilot.commands.search_provider import handle_search_provider_command
@@ -78,7 +79,29 @@ def completer(text, state):
7879
},
7980
},
8081
}
81-
TOOLS = [WEB_SEARCH_TOOL, EXEC_COMMAND_TOOL]
82+
83+
EDIT_TOOL = {
84+
"type": "function",
85+
"function": {
86+
"name": "edit",
87+
"description": "Apply a unified diff edit to a file on the local system.",
88+
"parameters": {
89+
"type": "object",
90+
"properties": {
91+
"file_path": {
92+
"type": "string",
93+
"description": "The path to the file to edit.",
94+
},
95+
"edit_content": {
96+
"type": "string",
97+
"description": "The unified diff content to apply.",
98+
},
99+
},
100+
"required": ["file_path", "edit_content"],
101+
},
102+
},
103+
}
104+
TOOLS = [WEB_SEARCH_TOOL, EXEC_COMMAND_TOOL, EDIT_TOOL]
82105

83106

84107
def load_github_token():
@@ -199,6 +222,23 @@ def main():
199222
"content": output,
200223
}
201224
)
225+
226+
if function_name == "edit":
227+
file_path = function_args.get("file_path")
228+
edit_content = function_args.get("edit_content")
229+
230+
result = EditTool.edit(file_path, edit_content)
231+
with open(file_path, "w") as f:
232+
f.write(result)
233+
234+
messages.append(
235+
{
236+
"tool_call_id": tool_call["id"],
237+
"role": "tool",
238+
"name": function_name,
239+
"content": f"Successfully edited {file_path}",
240+
}
241+
)
202242
response_message = chat(
203243
messages, copilot_token, current_model, tools=TOOLS
204244
)

0 commit comments

Comments
 (0)