aistvagent 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: aistvagent
3
+ Version: 1.0.0
4
+ Summary: AISTV - AI IT Agent cho Windows
5
+ Author: AISTV
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/aistv/agent
8
+ Project-URL: Source, https://github.com/aistv/agent
9
+ Keywords: ai,agent,windows,it-support,aistv
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: End Users/Desktop
12
+ Classifier: Operating System :: Microsoft :: Windows
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Desktop Environment
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: playwright>=1.40.0
22
+ Requires-Dist: pyautogui>=0.9.54
23
+ Requires-Dist: Pillow>=10.0.0
24
+
25
+ # AISTV - AI IT Agent cho Windows
26
+
27
+ ## Cai dat
28
+
29
+ ```bash
30
+ pip install .
31
+ playwright install chromium
32
+ ```
33
+
34
+ ## Su dung
35
+
36
+ ```bash
37
+ openaistv
38
+ ```
39
+
40
+ Mo trinh duyet: http://127.0.0.1:8765
@@ -0,0 +1,24 @@
1
+ openclaw/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
2
+ openclaw/__main__.py,sha256=3RlXYXmnGkuLxKGlGw1v9auVyT2poq3j7MAjKuOBuAY,38
3
+ openclaw/main.py,sha256=2KTlf7TPsYWWCyG-WYx2OZbvX97QXW5D9wYz80D0ing,4967
4
+ openclaw/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ openclaw/core/agent.py,sha256=HpVOU7cmD2sCgLP445ZaIYkTlap6_mIUdgHl5zY2Y_Q,8584
6
+ openclaw/core/function_registry.py,sha256=bDTXQQqAR9scyIoTA248G-J5bPItdVT9vLzwxHskPOk,2682
7
+ openclaw/skills/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ openclaw/skills/debugger.py,sha256=FRy7uncFmboLai4lLYsDBI6OQ_pTsj9oSlV3EQbHlfs,3012
9
+ openclaw/skills/file_manager.py,sha256=GRuxoZ0pCxWlBRIgX7uVIQwDKfVZU_PntuqGRwr9ff4,3463
10
+ openclaw/skills/os_control.py,sha256=3A1IXZJWAkXAgbmL5qDGjE4zb31-RxvM332U5A52BJ4,2067
11
+ openclaw/skills/software.py,sha256=xEBIEtZPttzpO7CCrnH5XGAFmMo5XRVwXyCaymuOSuY,2192
12
+ openclaw/skills/system.py,sha256=w0YcB1z6jifINHUlA1W3f-pBe9vRq3ZrM674PGSA2Oo,4741
13
+ openclaw/skills/web.py,sha256=QPdUotOEDuAg0bbmg55LFAE1GKJBkpybP47sXrRkfGo,5598
14
+ openclaw/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ openclaw/ui/server.py,sha256=YmP2-YVTSyS7qZaiIOAdOjDvHL9mtk_fO5pdTkKb3Bk,4567
16
+ openclaw/ui/static/index.html,sha256=MkRY8o8RF6jrq-uZfpiboRpjOZkFHSyAVeAp3bldOKw,1544
17
+ openclaw/ui/static/logo.jpg,sha256=cOLVwbJuktT7K0U14v_66SGjStEtHzZWTE2DKKOaZes,70489
18
+ openclaw/ui/static/script.js,sha256=KHO9wXLNKvsQH8Nr5dgGZZOGx5Pr1ctLkNWCNR9sbEg,2982
19
+ openclaw/ui/static/style.css,sha256=qYZKLEWrnDWQq6rlBU473Tp6V8i3KNZJ87qkybZAThc,7547
20
+ aistvagent-1.0.0.dist-info/METADATA,sha256=_UAqsxxtOkhdtTLN4_ivKTwuEllGCRM0R167Hr8sYIY,1120
21
+ aistvagent-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
22
+ aistvagent-1.0.0.dist-info/entry_points.txt,sha256=Fbaykzx9uRFlesrVAA8V-WJCOuTJ48fcZccMZZpttIE,49
23
+ aistvagent-1.0.0.dist-info/top_level.txt,sha256=_M92wW4knaMi1zhl9X_4pGiwCKofXax0qrlOnrU5seE,9
24
+ aistvagent-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ openaistv = openclaw.main:main
@@ -0,0 +1 @@
1
+ openclaw
openclaw/__init__.py ADDED
@@ -0,0 +1 @@
1
+
openclaw/__main__.py ADDED
@@ -0,0 +1,2 @@
1
+ from openclaw.main import main
2
+ main()
File without changes
openclaw/core/agent.py ADDED
@@ -0,0 +1,226 @@
1
+ import json
2
+ import subprocess
3
+ import re
4
+ import os
5
+
6
+ from .function_registry import FunctionRegistry
7
+
8
+
9
+ _AI_EXE = None
10
+
11
+
12
+ def _find_engine() -> str:
13
+ global _AI_EXE
14
+ if _AI_EXE:
15
+ return _AI_EXE
16
+ candidates = [
17
+ r"C:\npm\prefix\node_modules\opencode-ai\bin\opencode.exe",
18
+ os.path.expanduser(r"~\AppData\Roaming\npm\node_modules\opencode-ai\bin\opencode.exe"),
19
+ os.path.expanduser(r"~\AppData\Local\opencode\bin\opencode.exe"),
20
+ ]
21
+ for p in candidates:
22
+ if os.path.isfile(p):
23
+ _AI_EXE = p
24
+ return p
25
+ try:
26
+ r = subprocess.run("where opencode", capture_output=True, text=True, timeout=5, shell=True)
27
+ if r.returncode == 0:
28
+ path = r.stdout.strip().split("\n")[0].strip()
29
+ if path:
30
+ _AI_EXE = path
31
+ return path
32
+ except Exception:
33
+ pass
34
+ _AI_EXE = "opencode"
35
+ return "opencode"
36
+
37
+ TOOL_LIST = """
38
+ 1. get_disk_space - Kiem tra dung luong o dia
39
+ 2. clean_temp_files - Don rac he thong
40
+ 3. get_system_info - Thong tin he thong
41
+ 4. install_software(app_name) - Cai dat phan mem (VD: Discord.Discord)
42
+ 5. list_installed_software(filter_keyword) - Liet ke phan mem
43
+ 6. uninstall_software(app_name) - Go cai dat
44
+ 7. browse_and_search(url, search_query) - Mo trinh duyet + tim kiem
45
+ 8. capture_web_screenshot(url) - Chup anh web
46
+ 9. manage_file(action, file_path, content) - Doc/ghi/xoa file, liet ke thu muc
47
+ 10. find_large_files(directory, min_size_mb) - Tim file lon
48
+ 11. run_and_debug_script(file_path) - Chay script Python
49
+ 12. build_project(directory, build_tool) - Build project
50
+ 13. capture_screen(filename) - Chup man hinh
51
+ 14. mouse_click(x, y, button) - Click chuot
52
+ 15. keyboard_type(text) - Go chu
53
+ 16. press_key(key) - Nhan phim
54
+ 17. hotkey_combination(keys) - To hop phim
55
+ 18. execute_cmd(command) - Chay lenh CMD
56
+ """
57
+
58
+ SYSTEM_PROMPT = f"""Ban la AISTV, tro ly AI IT cho Windows.
59
+ {TOOL_LIST}
60
+ QUY TAC:
61
+ - Chon cong cu phu hop nhat.
62
+ - KHONG dung execute_cmd neu co cong cu chuyen dung.
63
+ - Tra ve JSON: {{"tool": "ten_cong_cu", "args": {{...}}}} neu can dung cong cu.
64
+ - Tra ve {{"text": "cau tra loi cua ban"}} neu khong can dung cong cu nao.
65
+ - KHONG dung "text" lam ten cong cu. "text" chi la truong trong JSON khi tra loi.
66
+ - Viet tieng Viet co dau."""
67
+
68
+
69
+ _AI_MODEL = "opencode/deepseek-v4-flash-free"
70
+
71
+
72
+ class Agent:
73
+ def __init__(self, api_key: str = ""):
74
+ self.api_key = api_key
75
+ self.registry = FunctionRegistry()
76
+ self.messages = []
77
+
78
+ def register_skill(self, fn=None, *, name: str = None, description: str = None):
79
+ return self.registry.register(fn, name=name, description=description)
80
+
81
+ def reset_conversation(self):
82
+ self.messages = []
83
+
84
+ def _build_prompt(self, user_input: str) -> str:
85
+ history = ""
86
+ for m in self.messages[-4:]:
87
+ role = "Nguoi dung" if m["role"] == "user" else "Tro ly"
88
+ history += f"{role}: {m['content']}\n"
89
+ return f"{SYSTEM_PROMPT}\n\nLICH SU:\n{history}\nNguoi dung: {user_input}\n\nTro ly (JSON):"
90
+
91
+ def _call_engine(self, prompt: str):
92
+ proc = subprocess.Popen(
93
+ [_find_engine(), "run", "--model", _AI_MODEL, "--format", "json",
94
+ "--dangerously-skip-permissions", prompt],
95
+ stdout=subprocess.PIPE,
96
+ stderr=subprocess.PIPE,
97
+ text=False,
98
+ )
99
+
100
+ for raw_line in iter(proc.stdout.readline, b''):
101
+ line = raw_line.decode("utf-8", errors="replace").strip()
102
+ if not line:
103
+ continue
104
+ try:
105
+ data = json.loads(line)
106
+ yield data
107
+ except json.JSONDecodeError:
108
+ pass
109
+
110
+ proc.wait()
111
+ if proc.returncode != 0:
112
+ err = proc.stderr.read().decode("utf-8", errors="replace")[:500]
113
+ yield {"type": "error", "content": err or f"Loi AI engine (exit {proc.returncode})"}
114
+
115
+ def _parse_json_response(self, text: str) -> dict:
116
+ text = text.strip()
117
+ match = re.search(r"\{.*\}", text, re.DOTALL)
118
+ if match:
119
+ try:
120
+ return json.loads(match.group())
121
+ except json.JSONDecodeError:
122
+ pass
123
+ try:
124
+ return json.loads(text)
125
+ except json.JSONDecodeError:
126
+ return {"text": text}
127
+
128
+ _TOOL_NAMES = {
129
+ "get_disk_space": "Kiem tra o dia",
130
+ "clean_temp_files": "Don rac he thong",
131
+ "get_system_info": "Xem thong tin he thong",
132
+ "install_software": "Cai dat phan mem",
133
+ "list_installed_software": "Liet ke phan mem",
134
+ "uninstall_software": "Go cai dat",
135
+ "browse_and_search": "Mo trinh duyet",
136
+ "capture_web_screenshot": "Chup anh web",
137
+ "manage_file": "Quan ly file",
138
+ "find_large_files": "Tim file lon",
139
+ "run_and_debug_script": "Chay script",
140
+ "build_project": "Build project",
141
+ "capture_screen": "Chup man hinh",
142
+ "mouse_click": "Click chuot",
143
+ "keyboard_type": "Go phim",
144
+ "press_key": "Nhan phim",
145
+ "hotkey_combination": "To hop phim",
146
+ "execute_cmd": "Chay lenh CMD",
147
+ }
148
+
149
+ def process_message_stream(self, user_input: str):
150
+ """Generator: yields dicts with step info for streaming display."""
151
+ yield {"type": "think", "content": "Dang phan tich yeu cau..."}
152
+ prompt = self._build_prompt(user_input)
153
+ raw_parts = []
154
+
155
+ for data in self._call_engine(prompt):
156
+ event = data.get("type", "")
157
+ if event == "text":
158
+ part = data.get("part", {})
159
+ text = part.get("text", "")
160
+ if text:
161
+ raw_parts.append(text)
162
+ elif event == "error":
163
+ yield {"type": "error", "content": f"Loi: {data.get('content', '')}"}
164
+ return
165
+
166
+ raw = "".join(raw_parts)
167
+ parsed = self._parse_json_response(raw)
168
+
169
+ if "tool" not in parsed:
170
+ text = parsed.get("text", raw)
171
+ yield {"type": "final_answer", "content": text}
172
+ self.messages.append({"role": "user", "content": user_input})
173
+ self.messages.append({"role": "assistant", "content": text})
174
+ return
175
+
176
+ fn_name = parsed["tool"]
177
+ fn_args = parsed.get("args", {})
178
+
179
+ # Neu AI tra ve {"tool": "text", "args": {"content/text": "..."}} -> xu ly nhu text response
180
+ if fn_name == "text":
181
+ text = fn_args.get("content") or fn_args.get("text") or ""
182
+ yield {"type": "final_answer", "content": text}
183
+ self.messages.append({"role": "user", "content": user_input})
184
+ self.messages.append({"role": "assistant", "content": text})
185
+ return
186
+
187
+ label = self._TOOL_NAMES.get(fn_name, fn_name)
188
+ yield {"type": "think", "content": f"Dang thuc thi: {label}..."}
189
+ yield {"type": "tool_call", "tool": fn_name, "arguments": fn_args}
190
+
191
+ try:
192
+ result = self.registry.execute(fn_name, fn_args)
193
+ except Exception as e:
194
+ result = f"Loi khi thuc thi {fn_name}: {str(e)}"
195
+
196
+ yield {"type": "think", "content": f"Da thuc thi xong: {label}"}
197
+ yield {"type": "tool_result", "tool": fn_name, "result": result}
198
+
199
+ final = self._format_result(fn_name, fn_args, result)
200
+ yield {"type": "final_answer", "content": final}
201
+ self.messages.append({"role": "user", "content": user_input})
202
+ self.messages.append({"role": "assistant", "content": final})
203
+
204
+ def _format_result(self, tool: str, args: dict, result: str) -> str:
205
+ labels = {
206
+ "get_disk_space": "Ket qua kiem tra o dia",
207
+ "clean_temp_files": "Ket qua don rac he thong",
208
+ "get_system_info": "Thong tin he thong",
209
+ "install_software": "Cai dat phan mem",
210
+ "list_installed_software": "Danh sach phan mem",
211
+ "uninstall_software": "Go cai dat phan mem",
212
+ "browse_and_search": "Trinh duyet web",
213
+ "capture_web_screenshot": "Chup anh web",
214
+ "manage_file": "Quan ly file",
215
+ "find_large_files": "Tim file lon",
216
+ "run_and_debug_script": "Chay script",
217
+ "build_project": "Build project",
218
+ "capture_screen": "Chup man hinh",
219
+ "mouse_click": "Click chuot",
220
+ "keyboard_type": "Go phim",
221
+ "press_key": "Nhan phim",
222
+ "hotkey_combination": "To hop phim",
223
+ "execute_cmd": "Ket qua lenh",
224
+ }
225
+ label = labels.get(tool, "Ket qua")
226
+ return f"{label}:\n{result}"
@@ -0,0 +1,84 @@
1
+ import inspect
2
+ import json
3
+ from typing import Any, Callable
4
+
5
+
6
+ class Tool:
7
+ def __init__(self, fn: Callable, name: str = None, description: str = None):
8
+ self.fn = fn
9
+ self.name = name or fn.__name__
10
+ self.description = description or (fn.__doc__ or "").strip()
11
+
12
+ sig = inspect.signature(fn)
13
+ self.parameters = {
14
+ "type": "object",
15
+ "properties": {},
16
+ "required": [],
17
+ }
18
+ for param_name, param in sig.parameters.items():
19
+ annotation = param.annotation
20
+ if annotation is inspect.Parameter.empty:
21
+ param_type = "string"
22
+ elif annotation is str:
23
+ param_type = "string"
24
+ elif annotation is int:
25
+ param_type = "integer"
26
+ elif annotation is bool:
27
+ param_type = "boolean"
28
+ elif annotation is float:
29
+ param_type = "number"
30
+ else:
31
+ param_type = "string"
32
+
33
+ self.parameters["properties"][param_name] = {
34
+ "type": param_type,
35
+ "description": f"Parameter {param_name}",
36
+ }
37
+ if param.default is inspect.Parameter.empty:
38
+ self.parameters["required"].append(param_name)
39
+
40
+ def to_openai_tool(self) -> dict:
41
+ return {
42
+ "type": "function",
43
+ "function": {
44
+ "name": self.name,
45
+ "description": self.description,
46
+ "parameters": self.parameters,
47
+ },
48
+ }
49
+
50
+ def run(self, **kwargs) -> Any:
51
+ return self.fn(**kwargs)
52
+
53
+
54
+ class FunctionRegistry:
55
+ def __init__(self):
56
+ self._tools: dict[str, Tool] = {}
57
+
58
+ def register(self, fn: Callable = None, *, name: str = None, description: str = None):
59
+ def wrapper(f: Callable):
60
+ tool = Tool(f, name=name, description=description)
61
+ self._tools[tool.name] = tool
62
+ return f
63
+ if fn is not None:
64
+ return wrapper(fn)
65
+ return wrapper
66
+
67
+ def get_tool(self, name: str) -> Tool | None:
68
+ return self._tools.get(name)
69
+
70
+ def list_tools(self) -> list[Tool]:
71
+ return list(self._tools.values())
72
+
73
+ def to_openai_tools(self) -> list[dict]:
74
+ return [t.to_openai_tool() for t in self._tools.values()]
75
+
76
+ def execute(self, name: str, arguments: dict) -> Any:
77
+ tool = self.get_tool(name)
78
+ if not tool:
79
+ return json.dumps({"error": f"Tool '{name}' not found"})
80
+ try:
81
+ result = tool.run(**arguments)
82
+ return str(result)
83
+ except Exception as e:
84
+ return json.dumps({"error": str(e)})
openclaw/main.py ADDED
@@ -0,0 +1,174 @@
1
+ import subprocess
2
+ import sys
3
+ import os
4
+ import webbrowser
5
+ import threading
6
+ import time
7
+
8
+ from openclaw.core.agent import Agent
9
+ from openclaw.ui.server import run_server
10
+
11
+
12
+ if hasattr(sys.stdout, "reconfigure"):
13
+ sys.stdout.reconfigure(encoding="utf-8")
14
+ if hasattr(sys.stderr, "reconfigure"):
15
+ sys.stderr.reconfigure(encoding="utf-8")
16
+
17
+
18
+ SPINNER = r"-\|/|"
19
+
20
+
21
+ def _spinner(stop, text):
22
+ i = 0
23
+ while not stop.is_set():
24
+ sym = SPINNER[i % len(SPINNER)]
25
+ print(f"\r{sym} {text}", end="", flush=True)
26
+ i += 1
27
+ time.sleep(0.1)
28
+ print(f"\r=> {text}")
29
+
30
+
31
+ def _run(cmd, timeout=120, shell=False):
32
+ if not shell and os.name == "nt":
33
+ shell = True
34
+ return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout, shell=shell)
35
+
36
+
37
+ def _check_node() -> bool:
38
+ try:
39
+ r = _run("node --version", timeout=5)
40
+ return r.returncode == 0
41
+ except Exception:
42
+ return False
43
+
44
+
45
+ def _check_npm() -> bool:
46
+ try:
47
+ r = _run("npm --version", timeout=5)
48
+ return r.returncode == 0
49
+ except Exception:
50
+ return False
51
+
52
+
53
+ def _setup() -> bool:
54
+ # ---------- Node.js ----------
55
+ stop = threading.Event()
56
+ t = threading.Thread(target=_spinner, args=(stop, "Kiem tra Node.js..."), daemon=True)
57
+ t.start()
58
+
59
+ has_node = _check_node()
60
+ has_npm = _check_npm()
61
+ stop.set(); t.join()
62
+
63
+ if not has_node:
64
+ print("\r[!] Can Node.js: https://nodejs.org")
65
+ return False
66
+
67
+ if not has_npm:
68
+ print("\r[!] Can npm (Node.js khong day du)")
69
+ return False
70
+
71
+ # ---------- AI Engine ----------
72
+ stop = threading.Event()
73
+ t = threading.Thread(target=_spinner, args=(stop, "Kiem tra AI engine..."), daemon=True)
74
+ t.start()
75
+
76
+ found = False
77
+ try:
78
+ r = _run("where opencode", timeout=5)
79
+ if r.returncode == 0 and r.stdout.strip():
80
+ found = True
81
+ except Exception:
82
+ pass
83
+ if not found:
84
+ for p in [
85
+ r"C:\npm\prefix\node_modules\opencode-ai\bin\opencode.exe",
86
+ os.path.expanduser(r"~\AppData\Roaming\npm\node_modules\opencode-ai\bin\opencode.exe"),
87
+ ]:
88
+ if os.path.isfile(p):
89
+ found = True
90
+ break
91
+
92
+ if not found:
93
+ stop.set(); t.join()
94
+ t = threading.Thread(target=_spinner, args=(threading.Event(), "Dang cai AI engine..."), daemon=True)
95
+ t.start()
96
+ try:
97
+ r = _run("npm i -g opencode-ai", timeout=180)
98
+ found = r.returncode == 0
99
+ except Exception as e:
100
+ print(f"\r[!] Loi cai dat AI engine: {e}")
101
+ return False
102
+
103
+ stop.set(); t.join()
104
+
105
+ if not found:
106
+ print("\r[!] Khong tim thay AI engine")
107
+ return False
108
+
109
+ # ---------- Playwright browser ----------
110
+ stop = threading.Event()
111
+ t = threading.Thread(target=_spinner, args=(stop, "Kiem tra trinh duyet..."), daemon=True)
112
+ t.start()
113
+
114
+ need_install = False
115
+ try:
116
+ from playwright.sync_api import sync_playwright
117
+ with sync_playwright() as p:
118
+ b = p.chromium.launch(headless=True)
119
+ b.close()
120
+ except Exception:
121
+ need_install = True
122
+
123
+ if need_install:
124
+ stop.set(); t.join()
125
+ t = threading.Thread(target=_spinner, args=(threading.Event(), "Dang tai trinh duyet..."), daemon=True)
126
+ t.start()
127
+ try:
128
+ _run("playwright install chromium", timeout=300)
129
+ except Exception:
130
+ pass
131
+
132
+ stop.set(); t.join()
133
+
134
+ return True
135
+
136
+
137
+ def register_all_skills(agent: Agent):
138
+ from openclaw.skills.system import execute_cmd, get_disk_space, clean_temp_files, get_system_info
139
+ from openclaw.skills.software import install_software, list_installed_software, uninstall_software
140
+ from openclaw.skills.web import browse_and_search, capture_web_screenshot
141
+ from openclaw.skills.file_manager import manage_file, find_large_files
142
+ from openclaw.skills.debugger import run_and_debug_script, build_project
143
+ from openclaw.skills.os_control import capture_screen, mouse_click, keyboard_type, press_key, hotkey_combination
144
+
145
+ for fn in [
146
+ execute_cmd, get_disk_space, clean_temp_files, get_system_info,
147
+ install_software, list_installed_software, uninstall_software,
148
+ browse_and_search, capture_web_screenshot,
149
+ manage_file, find_large_files,
150
+ run_and_debug_script, build_project,
151
+ capture_screen, mouse_click, keyboard_type, press_key, hotkey_combination,
152
+ ]:
153
+ agent.register_skill(fn)
154
+
155
+
156
+ def main():
157
+ print("AISTV - AI IT Agent cho Windows\n")
158
+
159
+ if not _setup():
160
+ sys.exit(1)
161
+
162
+ print("Khoi dong AI...")
163
+ agent = Agent()
164
+ register_all_skills(agent)
165
+
166
+ url = "http://127.0.0.1:8765"
167
+ print(f"San sang: {len(agent.registry.list_tools())} skills")
168
+ print(f"\nMo trinh duyet: {url}")
169
+ webbrowser.open(url)
170
+ run_server(agent, host="127.0.0.1", port=8765)
171
+
172
+
173
+ if __name__ == "__main__":
174
+ main()
File without changes
@@ -0,0 +1,70 @@
1
+ import subprocess
2
+ import sys
3
+ import os
4
+
5
+
6
+ def build_project(directory: str = ".", build_tool: str = "") -> str:
7
+ """Build/compile project. Tu dong phat hien loai project (package.json -> npm run build, setup.py -> python setup.py, Cargo.toml -> cargo build, *.csproj -> dotnet build, Makefile -> make). Neu build_tool duoc chi thi, dung no."""
8
+ try:
9
+ if build_tool:
10
+ cmd = build_tool
11
+ else:
12
+ files = os.listdir(directory)
13
+ if "package.json" in files:
14
+ cmd = "npm run build"
15
+ elif "setup.py" in files or "pyproject.toml" in files:
16
+ cmd = f"{sys.executable} setup.py build" if "setup.py" in files else "pip install ."
17
+ elif "Cargo.toml" in files:
18
+ cmd = "cargo build"
19
+ elif any(f.endswith(".csproj") for f in files):
20
+ cmd = "dotnet build"
21
+ elif "Makefile" in files or "makefile" in files:
22
+ cmd = "make"
23
+ elif "go.mod" in files:
24
+ cmd = "go build"
25
+ else:
26
+ return f"Khong the tu dong phat hien loai project trong {directory}. Hay chi ro build_tool."
27
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=300, cwd=directory)
28
+ out = result.stdout or ""
29
+ if result.stderr:
30
+ out += f"\nSTDERR:\n{result.stderr}"
31
+ if result.returncode == 0:
32
+ return f"Build thanh cong (exit 0):\n{out[:2000]}"
33
+ return f"Build that bai (exit {result.returncode}):\n{out[:2000]}"
34
+ except subprocess.TimeoutExpired:
35
+ return "Loi: build qua 5 phut."
36
+ except Exception as e:
37
+ return f"Loi khi build: {str(e)}"
38
+
39
+
40
+ def run_and_debug_script(file_path: str, max_retries: int = 1) -> str:
41
+ """Chạy một file Python script và trả về output. Dùng khi người dùng nói 'chạy script', 'run code', 'debug file'"""
42
+ logs = []
43
+ python_exe = sys.executable
44
+
45
+ for attempt in range(1, max_retries + 1):
46
+ logs.append(f"--- Lần chạy thứ {attempt} ---")
47
+ try:
48
+ result = subprocess.run(
49
+ [python_exe, file_path],
50
+ capture_output=True,
51
+ text=True,
52
+ timeout=60,
53
+ )
54
+ output = ""
55
+ if result.stdout:
56
+ output += result.stdout
57
+ if result.stderr:
58
+ output += f"\n[STDERR]\n{result.stderr}"
59
+
60
+ if result.returncode == 0:
61
+ logs.append(f"Chạy thành công (exit code 0):\n{output}")
62
+ else:
63
+ logs.append(f"Chạy thất bại (exit code {result.returncode}):\n{output}")
64
+ logs.append("Hãy xem lỗi ở trên và sửa file, sau đó chạy lại.")
65
+ except subprocess.TimeoutExpired:
66
+ logs.append(f"Lỗi: Script chạy quá 60 giây (lần {attempt})")
67
+ except Exception as e:
68
+ logs.append(f"Lỗi hệ thống: {str(e)}")
69
+
70
+ return "\n".join(logs)