machineconfig 6.84__py3-none-any.whl → 6.86__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.
Potentially problematic release.
This version of machineconfig might be problematic. Click here for more details.
- machineconfig/cluster/sessions_managers/wt_local.py +16 -221
- machineconfig/cluster/sessions_managers/wt_local_manager.py +33 -174
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +39 -197
- machineconfig/cluster/sessions_managers/wt_utils/manager_persistence.py +52 -0
- machineconfig/cluster/sessions_managers/wt_utils/monitoring_helpers.py +50 -0
- machineconfig/cluster/sessions_managers/wt_utils/status_reporting.py +76 -0
- machineconfig/cluster/sessions_managers/wt_utils/wt_helpers.py +199 -0
- machineconfig/scripts/python/agents.py +18 -7
- machineconfig/scripts/python/ai/vscode_tasks.py +7 -2
- machineconfig/scripts/python/env_manager/path_manager_tui.py +1 -1
- machineconfig/scripts/python/fire_jobs.py +31 -66
- machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_crush.py +6 -5
- machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_cursor_agents.py +1 -1
- machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_gemini.py +2 -3
- machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_qwen.py +2 -2
- machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_help_launch.py +4 -4
- machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_helper_types.py +2 -2
- machineconfig/scripts/python/helpers_agents/templates/prompt.txt +6 -0
- machineconfig/scripts/python/helpers_agents/templates/template.sh +24 -0
- machineconfig/scripts/python/helpers_devops/cli_config.py +1 -1
- machineconfig/scripts/python/helpers_devops/cli_nw.py +50 -0
- machineconfig/scripts/python/helpers_devops/cli_self.py +3 -3
- machineconfig/scripts/python/helpers_devops/cli_utils.py +18 -1
- machineconfig/scripts/python/{helpers_fire/helpers4.py → helpers_fire_command/file_wrangler.py} +15 -0
- machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +1 -1
- machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +1 -1
- machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +1 -1
- machineconfig/scripts/python/nw/mount_nfs +1 -1
- machineconfig/scripts/python/nw/wifi_conn.py +1 -53
- machineconfig/scripts/python/sessions.py +1 -1
- machineconfig/scripts/python/terminal.py +46 -17
- machineconfig/scripts/python/utils.py +10 -21
- machineconfig/scripts/windows/mounts/mount_ssh.ps1 +1 -1
- machineconfig/scripts/windows/term.ps1 +48 -0
- machineconfig/setup_linux/web_shortcuts/interactive.sh +1 -1
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +1 -1
- machineconfig/utils/code.py +18 -13
- machineconfig/utils/installer.py +0 -1
- machineconfig/utils/meta.py +4 -3
- machineconfig/utils/path_helper.py +1 -1
- machineconfig/utils/scheduling.py +0 -2
- machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
- machineconfig/utils/ssh.py +2 -2
- machineconfig/utils/upgrade_packages.py +28 -24
- {machineconfig-6.84.dist-info → machineconfig-6.86.dist-info}/METADATA +1 -1
- {machineconfig-6.84.dist-info → machineconfig-6.86.dist-info}/RECORD +55 -52
- machineconfig/scripts/linux/warp-cli.sh +0 -122
- machineconfig/scripts/python/helpers_fire/prompt.txt +0 -2
- machineconfig/scripts/python/helpers_fire/template.sh +0 -15
- /machineconfig/scripts/python/{helpers_fire → helpers_agents}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_crush.json +0 -0
- /machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_help_search.py +0 -0
- /machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_load_balancer.py +0 -0
- /machineconfig/scripts/python/{helpers_fire → helpers_agents/templates}/template.ps1 +0 -0
- {machineconfig-6.84.dist-info → machineconfig-6.86.dist-info}/WHEEL +0 -0
- {machineconfig-6.84.dist-info → machineconfig-6.86.dist-info}/entry_points.txt +0 -0
- {machineconfig-6.84.dist-info → machineconfig-6.86.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import random
|
|
3
|
+
import string
|
|
4
|
+
import json
|
|
5
|
+
import shlex
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Any
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
POWERSHELL_CMD = "powershell" if __import__("platform").system().lower() == "windows" else "pwsh"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def generate_random_suffix(length: int) -> str:
|
|
18
|
+
"""Generate a random string suffix for unique PowerShell script names."""
|
|
19
|
+
return "".join(random.choices(string.ascii_lowercase + string.digits, k=length))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def parse_command(command: str) -> tuple[str, list[str]]:
|
|
23
|
+
try:
|
|
24
|
+
parts = shlex.split(command)
|
|
25
|
+
if not parts:
|
|
26
|
+
raise ValueError("Empty command provided")
|
|
27
|
+
return parts[0], parts[1:] if len(parts) > 1 else []
|
|
28
|
+
except ValueError as e:
|
|
29
|
+
logger.error(f"Error parsing command '{command}': {e}")
|
|
30
|
+
parts = command.split()
|
|
31
|
+
return parts[0] if parts else "", parts[1:] if len(parts) > 1 else []
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def escape_for_wt(text: str) -> str:
|
|
35
|
+
"""Escape text for use in Windows Terminal commands."""
|
|
36
|
+
text = text.replace('"', '""')
|
|
37
|
+
if " " in text or ";" in text or "&" in text or "|" in text:
|
|
38
|
+
return f'"{text}"'
|
|
39
|
+
return text
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def validate_layout_config(layout_config: LayoutConfig) -> None:
|
|
43
|
+
"""Validate layout configuration format and content."""
|
|
44
|
+
if not layout_config["layoutTabs"]:
|
|
45
|
+
raise ValueError("Layout must contain at least one tab")
|
|
46
|
+
for tab in layout_config["layoutTabs"]:
|
|
47
|
+
if not tab["tabName"].strip():
|
|
48
|
+
raise ValueError(f"Invalid tab name: {tab['tabName']}")
|
|
49
|
+
if not tab["command"].strip():
|
|
50
|
+
raise ValueError(f"Invalid command for tab '{tab['tabName']}': {tab['command']}")
|
|
51
|
+
if not tab["startDir"].strip():
|
|
52
|
+
raise ValueError(f"Invalid startDir for tab '{tab['tabName']}': {tab['startDir']}")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def generate_wt_command_string(layout_config: LayoutConfig, window_name: str) -> str:
|
|
56
|
+
"""Generate complete Windows Terminal command string."""
|
|
57
|
+
command_parts = []
|
|
58
|
+
|
|
59
|
+
for i, tab in enumerate(layout_config["layoutTabs"]):
|
|
60
|
+
is_first = i == 0
|
|
61
|
+
|
|
62
|
+
if is_first:
|
|
63
|
+
tab_parts = ["wt", "-w", escape_for_wt(window_name)]
|
|
64
|
+
else:
|
|
65
|
+
tab_parts = ["new-tab"]
|
|
66
|
+
|
|
67
|
+
tab_name = tab["tabName"]
|
|
68
|
+
cwd = tab["startDir"]
|
|
69
|
+
command = tab["command"]
|
|
70
|
+
|
|
71
|
+
if cwd.startswith("~/"):
|
|
72
|
+
cwd = cwd.replace("~/", f"{Path.home()}/")
|
|
73
|
+
elif cwd == "~":
|
|
74
|
+
cwd = str(Path.home())
|
|
75
|
+
|
|
76
|
+
tab_parts.extend(["-d", escape_for_wt(cwd)])
|
|
77
|
+
tab_parts.extend(["--title", escape_for_wt(tab_name)])
|
|
78
|
+
tab_parts.append("--")
|
|
79
|
+
|
|
80
|
+
# Split the command into arguments
|
|
81
|
+
command_args = shlex.split(command)
|
|
82
|
+
tab_parts.extend(command_args)
|
|
83
|
+
|
|
84
|
+
command_parts.append(" ".join(tab_parts))
|
|
85
|
+
|
|
86
|
+
return " `; ".join(command_parts)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def check_wt_session_status(session_name: str) -> dict[str, Any]:
|
|
90
|
+
try:
|
|
91
|
+
ps_script = """
|
|
92
|
+
try {
|
|
93
|
+
$wtProcesses = Get-Process -Name 'WindowsTerminal' -ErrorAction SilentlyContinue
|
|
94
|
+
if ($wtProcesses) {
|
|
95
|
+
$processInfo = @()
|
|
96
|
+
$wtProcesses | ForEach-Object {
|
|
97
|
+
$info = @{
|
|
98
|
+
"Id" = $_.Id
|
|
99
|
+
"ProcessName" = $_.ProcessName
|
|
100
|
+
"StartTime" = $_.StartTime.ToString()
|
|
101
|
+
}
|
|
102
|
+
$processInfo += $info
|
|
103
|
+
}
|
|
104
|
+
$processInfo | ConvertTo-Json -Depth 2
|
|
105
|
+
}
|
|
106
|
+
} catch {
|
|
107
|
+
# No Windows Terminal processes found
|
|
108
|
+
}
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
result = subprocess.run([POWERSHELL_CMD, "-Command", ps_script], capture_output=True, text=True, timeout=5)
|
|
112
|
+
|
|
113
|
+
if result.returncode == 0:
|
|
114
|
+
output = result.stdout.strip()
|
|
115
|
+
if output and output != "":
|
|
116
|
+
try:
|
|
117
|
+
processes = json.loads(output)
|
|
118
|
+
if not isinstance(processes, list):
|
|
119
|
+
processes = [processes]
|
|
120
|
+
|
|
121
|
+
return {"wt_running": True, "session_exists": len(processes) > 0, "session_name": session_name, "all_windows": processes, "session_windows": processes}
|
|
122
|
+
except Exception as e:
|
|
123
|
+
return {"wt_running": True, "session_exists": False, "error": f"Failed to parse process info: {e}", "session_name": session_name}
|
|
124
|
+
else:
|
|
125
|
+
return {"wt_running": False, "session_exists": False, "session_name": session_name, "all_windows": []}
|
|
126
|
+
else:
|
|
127
|
+
return {"wt_running": False, "error": result.stderr, "session_name": session_name}
|
|
128
|
+
|
|
129
|
+
except subprocess.TimeoutExpired:
|
|
130
|
+
return {"wt_running": False, "error": "Timeout while checking Windows Terminal processes", "session_name": session_name}
|
|
131
|
+
except FileNotFoundError:
|
|
132
|
+
return {"wt_running": False, "error": f"PowerShell ({POWERSHELL_CMD}) not found in PATH", "session_name": session_name}
|
|
133
|
+
except Exception as e:
|
|
134
|
+
return {"wt_running": False, "error": str(e), "session_name": session_name}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def check_command_status(tab_name: str, layout_config: LayoutConfig) -> dict[str, Any]:
|
|
138
|
+
"""Check if a command is running by looking for processes."""
|
|
139
|
+
tab_config = None
|
|
140
|
+
for tab in layout_config["layoutTabs"]:
|
|
141
|
+
if tab["tabName"] == tab_name:
|
|
142
|
+
tab_config = tab
|
|
143
|
+
break
|
|
144
|
+
|
|
145
|
+
if tab_config is None:
|
|
146
|
+
return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "pid": None, "command": None}
|
|
147
|
+
|
|
148
|
+
command = tab_config["command"]
|
|
149
|
+
|
|
150
|
+
try:
|
|
151
|
+
primary_cmd = command.split()[0] if command.strip() else ""
|
|
152
|
+
if not primary_cmd:
|
|
153
|
+
return {"status": "error", "error": "Empty command", "running": False, "command": command, "tab_name": tab_name}
|
|
154
|
+
|
|
155
|
+
ps_script = f"""
|
|
156
|
+
try {{
|
|
157
|
+
$processes = Get-Process -Name '{primary_cmd}' -ErrorAction SilentlyContinue
|
|
158
|
+
if ($processes) {{
|
|
159
|
+
$processes | ForEach-Object {{
|
|
160
|
+
$procInfo = @{{
|
|
161
|
+
"pid" = $_.Id
|
|
162
|
+
"name" = $_.ProcessName
|
|
163
|
+
"start_time" = $_.StartTime.ToString()
|
|
164
|
+
}}
|
|
165
|
+
Write-Output ($procInfo | ConvertTo-Json -Compress)
|
|
166
|
+
}}
|
|
167
|
+
}}
|
|
168
|
+
}} catch {{
|
|
169
|
+
# No processes found or other error
|
|
170
|
+
}}
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
result = subprocess.run([POWERSHELL_CMD, "-Command", ps_script], capture_output=True, text=True, timeout=5)
|
|
174
|
+
|
|
175
|
+
if result.returncode == 0:
|
|
176
|
+
output_lines = [line.strip() for line in result.stdout.strip().split("\n") if line.strip()]
|
|
177
|
+
matching_processes = []
|
|
178
|
+
|
|
179
|
+
for line in output_lines:
|
|
180
|
+
if line.startswith("{") and line.endswith("}"):
|
|
181
|
+
try:
|
|
182
|
+
proc_info = json.loads(line)
|
|
183
|
+
matching_processes.append(proc_info)
|
|
184
|
+
except json.JSONDecodeError:
|
|
185
|
+
continue
|
|
186
|
+
|
|
187
|
+
if matching_processes:
|
|
188
|
+
return {"status": "running", "running": True, "processes": matching_processes, "command": command, "tab_name": tab_name}
|
|
189
|
+
else:
|
|
190
|
+
return {"status": "not_running", "running": False, "processes": [], "command": command, "tab_name": tab_name}
|
|
191
|
+
else:
|
|
192
|
+
return {"status": "error", "error": f"Command failed: {result.stderr}", "running": False, "command": command, "tab_name": tab_name}
|
|
193
|
+
|
|
194
|
+
except subprocess.TimeoutExpired:
|
|
195
|
+
logger.error(f"Timeout checking command status for tab '{tab_name}'")
|
|
196
|
+
return {"status": "timeout", "error": "Timeout checking process status", "running": False, "command": command, "tab_name": tab_name}
|
|
197
|
+
except Exception as e:
|
|
198
|
+
logger.error(f"Error checking command status for tab '{tab_name}': {e}")
|
|
199
|
+
return {"status": "error", "error": str(e), "running": False, "command": command, "tab_name": tab_name}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import cast, Optional, get_args, Annotated
|
|
7
7
|
import typer
|
|
8
|
-
from machineconfig.scripts.python.
|
|
8
|
+
from machineconfig.scripts.python.helpers_agents.fire_agents_helper_types import AGENTS, HOST, MODEL, PROVIDER
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def create(
|
|
@@ -24,11 +24,22 @@ def create(
|
|
|
24
24
|
agents_dir: Annotated[Optional[Path], typer.Option(..., "--agents-dir", "-ad", help="Directory to store agent files. If not provided, will be constructed automatically.")] = None,
|
|
25
25
|
):
|
|
26
26
|
|
|
27
|
-
from machineconfig.scripts.python.
|
|
28
|
-
from machineconfig.scripts.python.
|
|
27
|
+
from machineconfig.scripts.python.helpers_agents.fire_agents_help_launch import prep_agent_launch, get_agents_launch_layout
|
|
28
|
+
from machineconfig.scripts.python.helpers_agents.fire_agents_load_balancer import chunk_prompts
|
|
29
|
+
from machineconfig.scripts.python.helpers_agents.fire_agents_helper_types import PROVIDER2MODEL
|
|
29
30
|
from machineconfig.utils.accessories import get_repo_root, randstr
|
|
30
31
|
import json
|
|
31
32
|
|
|
33
|
+
# validate model is valid for the provider
|
|
34
|
+
valid_models_for_provider = PROVIDER2MODEL.get(provider, [])
|
|
35
|
+
if model not in valid_models_for_provider:
|
|
36
|
+
available_models = "\n ".join(valid_models_for_provider) if valid_models_for_provider else "(none configured)"
|
|
37
|
+
raise typer.BadParameter(
|
|
38
|
+
f"Model '{model}' is not valid for provider '{provider}'.\n"
|
|
39
|
+
f"Valid models for '{provider}':\n {available_models}\n"
|
|
40
|
+
f"All available models: {', '.join(get_args(MODEL))}"
|
|
41
|
+
)
|
|
42
|
+
|
|
32
43
|
# validate mutual exclusive
|
|
33
44
|
prompt_options = [prompt, prompt_path]
|
|
34
45
|
provided_prompt = [opt for opt in prompt_options if opt is not None]
|
|
@@ -85,7 +96,7 @@ agents create "{context_path_resolved}" \\
|
|
|
85
96
|
--separator "{separator}" \\
|
|
86
97
|
{"--separate" if separate else ""}
|
|
87
98
|
"""
|
|
88
|
-
(agents_dir / "aa_agents_relaunch.
|
|
99
|
+
(agents_dir / "aa_agents_relaunch.sh").write_text(data=regenerate_py_code, encoding="utf-8")
|
|
89
100
|
layout_output_path = output_path if output_path is not None else agents_dir / "layout.json"
|
|
90
101
|
layout_output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
91
102
|
layout_output_path.write_text(data=json.dumps(layoutfile, indent=4), encoding="utf-8")
|
|
@@ -136,11 +147,11 @@ def collect(
|
|
|
136
147
|
|
|
137
148
|
def template():
|
|
138
149
|
from platform import system
|
|
139
|
-
import machineconfig.scripts.python.
|
|
150
|
+
import machineconfig.scripts.python.helpers_agents as module
|
|
140
151
|
if system() == "Linux" or system() == "Darwin":
|
|
141
|
-
template_path = Path(module.__file__).parent / "template.sh"
|
|
152
|
+
template_path = Path(module.__file__).parent / "templates/template.sh"
|
|
142
153
|
elif system() == "Windows":
|
|
143
|
-
template_path = Path(module.__file__).parent / "template.ps1"
|
|
154
|
+
template_path = Path(module.__file__).parent / "templates/template.ps1"
|
|
144
155
|
else:
|
|
145
156
|
raise typer.BadParameter(f"Unsupported OS: {system()}")
|
|
146
157
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from typing import Any
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
def add_lint_and_type_check_task(repo_root: Path) -> None:
|
|
@@ -18,8 +19,12 @@ def add_lint_and_type_check_task(repo_root: Path) -> None:
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
if tasks_json_path.exists():
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
json_data = tasks_json_path.read_text(encoding="utf-8")
|
|
23
|
+
if not json_data.strip():
|
|
24
|
+
tasks_config: dict[str, Any] = {"version": "2.0.0", "tasks": []}
|
|
25
|
+
else:
|
|
26
|
+
tasks_config = json.loads(json_data)
|
|
27
|
+
assert isinstance(tasks_config, dict)
|
|
23
28
|
if "tasks" not in tasks_config:
|
|
24
29
|
tasks_config["tasks"] = []
|
|
25
30
|
existing_labels = {task.get("label") for task in tasks_config.get("tasks", [])}
|
|
@@ -7,7 +7,7 @@ fire
|
|
|
7
7
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
from machineconfig.utils.ve import
|
|
10
|
+
from machineconfig.utils.ve import get_ve_path_and_ipython_profile
|
|
11
11
|
from machineconfig.utils.options import choose_from_options
|
|
12
12
|
from machineconfig.utils.path_helper import match_file_name, sanitize_path
|
|
13
13
|
from machineconfig.utils.path_extended import PathExtended
|
|
@@ -26,7 +26,7 @@ def route(args: FireJobArgs, fire_args: str = "") -> None:
|
|
|
26
26
|
suffixes = {".py", ".sh", ".ps1"}
|
|
27
27
|
choice_file = match_file_name(sub_string=args.path, search_root=PathExtended.cwd(), suffixes=suffixes)
|
|
28
28
|
elif path_obj.is_dir():
|
|
29
|
-
from machineconfig.scripts.python.
|
|
29
|
+
from machineconfig.scripts.python.helpers_fire_command.file_wrangler import search_for_files_of_interest
|
|
30
30
|
print(f"🔍 Searching recursively for Python, PowerShell and Shell scripts in directory `{path_obj}`")
|
|
31
31
|
files = search_for_files_of_interest(path_obj)
|
|
32
32
|
print(f"🔍 Got #{len(files)} results.")
|
|
@@ -38,10 +38,6 @@ def route(args: FireJobArgs, fire_args: str = "") -> None:
|
|
|
38
38
|
|
|
39
39
|
repo_root = get_repo_root(Path(choice_file))
|
|
40
40
|
print(f"💾 Selected file: {choice_file}.\nRepo root: {repo_root}")
|
|
41
|
-
ve_root_from_file, ipy_profile = get_ve_path_and_ipython_profile(choice_file)
|
|
42
|
-
if ipy_profile is None:
|
|
43
|
-
ipy_profile = "default"
|
|
44
|
-
|
|
45
41
|
if args.marimo:
|
|
46
42
|
tmp_dir = PathExtended.tmp().joinpath(f"tmp_scripts/marimo/{choice_file.stem}_{randstr()}")
|
|
47
43
|
tmp_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -58,15 +54,9 @@ uv run --project {repo_root} --with marimo marimo edit --host 0.0.0.0 marimo_nb.
|
|
|
58
54
|
# ========================= preparing kwargs_dict
|
|
59
55
|
if choice_file.suffix == ".py":
|
|
60
56
|
kwargs_dict = extract_kwargs(args) # This now returns empty dict, but kept for compatibility
|
|
61
|
-
ve_root = args.ve or ve_root_from_file
|
|
62
|
-
if ve_root is None:
|
|
63
|
-
raise ValueError(f"Could not determine virtual environment for file {choice_file}. Please ensure it is within a recognized project structure or specify the `--ve` option.")
|
|
64
|
-
activate_ve_line = get_ve_activate_line(ve_root=ve_root)
|
|
65
57
|
else:
|
|
66
|
-
activate_ve_line = ""
|
|
67
58
|
kwargs_dict = {}
|
|
68
59
|
|
|
69
|
-
|
|
70
60
|
# ========================= choosing function to run
|
|
71
61
|
choice_function: Optional[str] = None # Initialize to avoid unbound variable
|
|
72
62
|
if args.choose_function:
|
|
@@ -77,58 +67,35 @@ uv run --project {repo_root} --with marimo marimo edit --host 0.0.0.0 marimo_nb.
|
|
|
77
67
|
|
|
78
68
|
if choice_file.suffix == ".py":
|
|
79
69
|
from machineconfig.scripts.python.helpers_fire_command.fire_jobs_route_helper import get_command_streamlit
|
|
80
|
-
if args.streamlit:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
70
|
+
if args.streamlit:
|
|
71
|
+
exe = get_command_streamlit(choice_file=choice_file, environment=args.environment, repo_root=repo_root)
|
|
72
|
+
exe = f"uv run {exe} "
|
|
73
|
+
elif args.jupyter: exe = "uv run jupyter-lab"
|
|
74
|
+
else:
|
|
75
|
+
if args.interactive:
|
|
76
|
+
_ve_root_from_file, ipy_profile = get_ve_path_and_ipython_profile(choice_file)
|
|
77
|
+
if ipy_profile is None:
|
|
78
|
+
ipy_profile = "default"
|
|
79
|
+
exe = f"uv run ipython -i --no-banner --profile {ipy_profile} "
|
|
80
|
+
else:
|
|
81
|
+
exe = "uv run python "
|
|
84
82
|
elif choice_file.suffix == ".ps1" or choice_file.suffix == ".sh": exe = "."
|
|
85
83
|
elif choice_file.suffix == "": exe = ""
|
|
86
84
|
else: raise NotImplementedError(f"File type {choice_file.suffix} not supported, in the sense that I don't know how to fire it.")
|
|
87
85
|
|
|
88
86
|
if args.module or (args.debug and args.choose_function): # because debugging tools do not support choosing functions and don't interplay with fire module. So the only way to have debugging and choose function options is to import the file as a module into a new script and run the function of interest there and debug the new script.
|
|
89
87
|
assert choice_file.suffix == ".py", f"File must be a python file to be imported as a module. Got {choice_file}"
|
|
90
|
-
from machineconfig.scripts.python.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
else
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
except (ImportError, ModuleNotFoundError) as ex:
|
|
100
|
-
print(fr"❌ Failed to import `{choice_file}` as a module: {{ex}} ")
|
|
101
|
-
print(fr"⚠️ Attempting import with ad-hoc `$PATH` manipulation. DO NOT pickle any objects in this session as correct deserialization cannot be guaranteed.")
|
|
102
|
-
import sys
|
|
103
|
-
sys.path.append(r'{PathExtended(choice_file).parent}')
|
|
104
|
-
{repo_root_add}
|
|
105
|
-
from {PathExtended(choice_file).stem} import *
|
|
106
|
-
print(fr"✅ Successfully imported `{choice_file}`")
|
|
107
|
-
"""
|
|
108
|
-
if choice_function is not None:
|
|
109
|
-
txt = (
|
|
110
|
-
txt
|
|
111
|
-
+ f"""
|
|
112
|
-
res = {choice_function}({("**" + str(kwargs_dict)) if kwargs_dict else ""})
|
|
113
|
-
"""
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
txt = (
|
|
117
|
-
f"""
|
|
118
|
-
try:
|
|
119
|
-
from rich.panel import Panel
|
|
120
|
-
from rich.console import Console
|
|
121
|
-
from rich.syntax import Syntax
|
|
122
|
-
console = Console()
|
|
123
|
-
console.print(Panel(Syntax(code=r'''{txt}''', lexer='python'), title='Import Script'), style="bold red")
|
|
124
|
-
except ImportError as _ex:
|
|
125
|
-
print(r'''{txt}''')
|
|
126
|
-
"""
|
|
127
|
-
+ txt
|
|
128
|
-
)
|
|
129
|
-
choice_file = PathExtended.tmp().joinpath(f"tmp_scripts/python/{PathExtended(choice_file).parent.name}_{PathExtended(choice_file).stem}_{randstr()}.py")
|
|
88
|
+
from machineconfig.scripts.python.helpers_fire_command.file_wrangler import get_import_module_code, wrap_import_in_try_except
|
|
89
|
+
from machineconfig.utils.meta import lambda_to_python_script
|
|
90
|
+
from machineconfig.utils.code import print_code
|
|
91
|
+
import_code = get_import_module_code(str(choice_file))
|
|
92
|
+
import_code_robust = lambda_to_python_script(lambda: wrap_import_in_try_except(import_line=import_code, pyfile=str(choice_file), repo_root=str(repo_root) if repo_root is not None else None), in_global=True, import_module=False)
|
|
93
|
+
code_printing = lambda_to_python_script(lambda: print_code(code=import_code_robust, lexer="python", desc="import code"), in_global=True, import_module=False)
|
|
94
|
+
if choice_function is not None: calling = f"""res = {choice_function}({("**" + str(kwargs_dict)) if kwargs_dict else ""})"""
|
|
95
|
+
else: calling = """# No function selected to call. You can add your code here."""
|
|
96
|
+
choice_file = Path.home().joinpath(f"tmp_results/tmp_scripts/python/{Path(choice_file).parent.name}_{Path(choice_file).stem}_{randstr()}.py")
|
|
130
97
|
choice_file.parent.mkdir(parents=True, exist_ok=True)
|
|
131
|
-
choice_file.write_text(
|
|
98
|
+
choice_file.write_text(import_code_robust + "\n" + code_printing + "\n" + calling, encoding="utf-8")
|
|
132
99
|
|
|
133
100
|
# ========================= determining basic command structure: putting together exe & choice_file & choice_function & pdb
|
|
134
101
|
if args.debug:
|
|
@@ -149,26 +116,24 @@ except ImportError as _ex:
|
|
|
149
116
|
command = f"{exe} {choice_file}"
|
|
150
117
|
else:
|
|
151
118
|
command = f"cd {choice_file.parent}\n{exe} {choice_file.name}\ncd {PathExtended.cwd()}"
|
|
152
|
-
|
|
153
119
|
elif args.cmd:
|
|
154
120
|
command = rf""" cd /d {choice_file.parent} & {exe} {choice_file.name} """
|
|
155
121
|
else:
|
|
156
122
|
if choice_file.suffix == "": command = f"{exe} {choice_file} {fire_args}"
|
|
157
123
|
else: command = f"{exe} {choice_file} "
|
|
158
124
|
|
|
159
|
-
|
|
125
|
+
|
|
126
|
+
if not args.cmd: pass
|
|
160
127
|
else:
|
|
161
128
|
new_line = "\n"
|
|
162
|
-
command = rf"""start cmd -Argument "/k {
|
|
129
|
+
command = rf"""start cmd -Argument "/k {command.replace(new_line, " & ")} " """ # this works from powershell
|
|
163
130
|
if args.submit_to_cloud:
|
|
164
|
-
command = f"""
|
|
165
|
-
{activate_ve_line}
|
|
166
|
-
python -m machineconfig.cluster.templates.cli_click --file {choice_file} """
|
|
131
|
+
command = f"""uv run python -m machineconfig.cluster.templates.cli_click --file {choice_file} """
|
|
167
132
|
if choice_function is not None:
|
|
168
133
|
command += f"--function {choice_function} "
|
|
169
134
|
|
|
170
|
-
if args.optimized:
|
|
171
|
-
|
|
135
|
+
if args.optimized: command = command.replace("python ", "python -OO ")
|
|
136
|
+
|
|
172
137
|
from rich.panel import Panel
|
|
173
138
|
from rich.console import Console
|
|
174
139
|
from rich.syntax import Syntax
|
|
@@ -207,7 +172,7 @@ python -m machineconfig.cluster.templates.cli_click --file {choice_file} """
|
|
|
207
172
|
import os
|
|
208
173
|
op_program_path = os.environ.get("OP_PROGRAM_PATH", None)
|
|
209
174
|
if op_program_path is not None:
|
|
210
|
-
op_program_path =
|
|
175
|
+
op_program_path = Path(op_program_path)
|
|
211
176
|
op_program_path.parent.mkdir(parents=True, exist_ok=True)
|
|
212
177
|
op_program_path.write_text(command, encoding="utf-8")
|
|
213
178
|
else:
|
machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_crush.py
RENAMED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
# import shlex
|
|
4
4
|
from typing import Optional
|
|
5
|
-
from machineconfig.scripts.python.
|
|
5
|
+
from machineconfig.scripts.python.helpers_agents.fire_agents_helper_types import HOST, PROVIDER, MODEL
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def fire_crush(api_key: Optional[str], model: MODEL, provider: PROVIDER, machine: HOST, prompt_path: Path, repo_root: Path) -> str:
|
|
@@ -16,21 +16,22 @@ crush run {prompt_path}
|
|
|
16
16
|
json_path = Path(__file__).parent / "fire_crush.json"
|
|
17
17
|
json_template = json_path.read_text(encoding="utf-8")
|
|
18
18
|
json_filled = json_template.replace("{api_key}", api_key).replace("{model}", model).replace("{provider}", provider)
|
|
19
|
-
import
|
|
20
|
-
temp_config_file_local =
|
|
19
|
+
from machineconfig.utils.accessories import randstr
|
|
20
|
+
temp_config_file_local = Path.home().joinpath("tmp_results/tmp_files/crush_" + randstr(8) + ".json")
|
|
21
|
+
temp_config_file_local.parent.mkdir(parents=True, exist_ok=True)
|
|
21
22
|
Path(temp_config_file_local).write_text(json_filled, encoding="utf-8")
|
|
22
23
|
cmd = f"""
|
|
23
24
|
|
|
24
25
|
# -e "PATH_PROMPT=$PATH_PROMPT"
|
|
25
26
|
# opencode --model "{provider}/{model}" run {prompt_path}
|
|
26
|
-
|
|
27
|
+
|
|
27
28
|
|
|
28
29
|
echo "Running prompt @ {prompt_path.relative_to(repo_root)} using Docker with Crush..."
|
|
29
30
|
docker run -it --rm \
|
|
30
31
|
-v "{repo_root}:/workspace/{repo_root.name}" \
|
|
31
32
|
-v "{temp_config_file_local}:/root/.local/share/crush/crush.json" \
|
|
32
33
|
-w "/workspace/{repo_root.name}" \
|
|
33
|
-
statistician/machineconfig:latest \
|
|
34
|
+
statistician/machineconfig-ai:latest \
|
|
34
35
|
bash -i -c "source ~/.bashrc && cd /workspace/{repo_root.name} && cat /root/.local/share/crush/crush.json && crush run 'Please act on contents of this prompt ./{prompt_path.relative_to(repo_root)}'"
|
|
35
36
|
|
|
36
37
|
"""
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
# import shlex
|
|
5
|
-
from machineconfig.scripts.python.
|
|
5
|
+
from machineconfig.scripts.python.helpers_agents.fire_agents_helper_types import HOST
|
|
6
6
|
from typing import Optional
|
|
7
7
|
|
|
8
8
|
def fire_cursor(api_key: Optional[str], prompt_path: Path, machine: HOST) -> str:
|
machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_gemini.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
import shlex
|
|
4
|
-
from machineconfig.scripts.python.
|
|
4
|
+
from machineconfig.scripts.python.helpers_agents.fire_agents_helper_types import HOST
|
|
5
5
|
from typing import Optional, Literal
|
|
6
6
|
|
|
7
7
|
|
|
@@ -37,8 +37,7 @@ docker run -it --rm \
|
|
|
37
37
|
-e GEMINI_API_KEY="{api_key}" \
|
|
38
38
|
-v "{repo_root}:/workspace/{repo_root.name}" \
|
|
39
39
|
-w "/workspace/{repo_root.name}" \
|
|
40
|
-
statistician/machineconfig:latest \
|
|
40
|
+
statistician/machineconfig-ai:latest \
|
|
41
41
|
gemini --prompt "$PATH_PROMPT"
|
|
42
42
|
"""
|
|
43
43
|
return cmd
|
|
44
|
-
|
machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_qwen.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
import shlex
|
|
4
|
-
from machineconfig.scripts.python.
|
|
4
|
+
from machineconfig.scripts.python.helpers_agents.fire_agents_helper_types import HOST
|
|
5
5
|
from typing import Optional, Literal
|
|
6
6
|
|
|
7
7
|
|
|
@@ -37,7 +37,7 @@ docker run -it --rm \
|
|
|
37
37
|
-v {shlex.quote(str(oauth_creds))}:/root/.qwen/oauth_creds.json \
|
|
38
38
|
-v {shlex.quote(str(settings))}:/root/.qwen/settings.json \
|
|
39
39
|
-w "/workspace/{repo_root.name}" \
|
|
40
|
-
statistician/machineconfig:latest \
|
|
40
|
+
statistician/machineconfig-ai:latest \
|
|
41
41
|
qwen --prompt "$PATH_PROMPT"
|
|
42
42
|
"""
|
|
43
43
|
return cmd
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import random
|
|
3
3
|
import shlex
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from machineconfig.scripts.python.
|
|
5
|
+
from machineconfig.scripts.python.helpers_agents.fire_agents_helper_types import AGENTS, AGENT_NAME_FORMATTER, HOST, PROVIDER, MODEL
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def get_api_keys(provider: PROVIDER) -> list[str]:
|
|
@@ -66,14 +66,14 @@ sleep 0.1
|
|
|
66
66
|
assert provider == "google", "Gemini agent only works with google provider."
|
|
67
67
|
api_keys = get_api_keys(provider="google")
|
|
68
68
|
api_key = api_keys[idx % len(api_keys)] if len(api_keys) > 0 else None
|
|
69
|
-
from machineconfig.scripts.python.
|
|
69
|
+
from machineconfig.scripts.python.helpers_agents.agentic_frameworks.fire_gemini import fire_gemini
|
|
70
70
|
cmd = fire_gemini(api_key=api_key, prompt_path=prompt_path, machine=machine, model="gemini-2.5-pro", provider="google", repo_root=repo_root)
|
|
71
71
|
case "cursor-agent":
|
|
72
|
-
from machineconfig.scripts.python.
|
|
72
|
+
from machineconfig.scripts.python.helpers_agents.agentic_frameworks.fire_cursor_agents import fire_cursor
|
|
73
73
|
cmd = fire_cursor(prompt_path=prompt_path, machine=machine, api_key=None)
|
|
74
74
|
raise NotImplementedError("Cursor agent is not implemented yet, api key missing")
|
|
75
75
|
case "crush":
|
|
76
|
-
from machineconfig.scripts.python.
|
|
76
|
+
from machineconfig.scripts.python.helpers_agents.agentic_frameworks.fire_crush import fire_crush
|
|
77
77
|
api_keys = get_api_keys(provider=provider)
|
|
78
78
|
api_key = api_keys[idx % len(api_keys)] if len(api_keys) > 0 else None
|
|
79
79
|
cmd = fire_crush(api_key=api_key, prompt_path=prompt_path, machine=machine, repo_root=repo_root, model=model, provider=provider)
|
|
@@ -20,7 +20,7 @@ AGENTS: TypeAlias = Literal["cursor-agent", "gemini", "qwen-code", "copilot", "c
|
|
|
20
20
|
HOST: TypeAlias = Literal["local", "docker"]
|
|
21
21
|
PROVIDER: TypeAlias = Literal["azure", "google", "aws", "openai", "anthropic", "openrouter", "xai"]
|
|
22
22
|
MODEL: TypeAlias = Literal["zai/glm-4.6", "anthropic/sonnet-4.5", "google/gemini-2.5-pro", "openai/gpt-5-codex",
|
|
23
|
-
"openrouter/supernova", "x-ai/grok-4-fast:free",
|
|
23
|
+
"openrouter/supernova", "openrouter/andromeda-alpha", "x-ai/grok-4-fast:free",
|
|
24
24
|
]
|
|
25
25
|
PROVIDER2MODEL: dict[PROVIDER, list[MODEL]] = {
|
|
26
26
|
"azure": ["zai/glm-4.6"],
|
|
@@ -28,7 +28,7 @@ PROVIDER2MODEL: dict[PROVIDER, list[MODEL]] = {
|
|
|
28
28
|
"aws": [],
|
|
29
29
|
"openai": ["openai/gpt-5-codex"],
|
|
30
30
|
"anthropic": ["anthropic/sonnet-4.5"],
|
|
31
|
-
"openrouter": ["openrouter/supernova"],
|
|
31
|
+
"openrouter": ["openrouter/supernova", "openrouter/andromeda-alpha"],
|
|
32
32
|
"xai": ["x-ai/grok-4-fast:free"]
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
#!/bin/bash
|
|
3
|
+
# set -e # Exit immediately if a command exits with a non-zero status.
|
|
4
|
+
|
|
5
|
+
JOB_NAME="outpatient_mapping"
|
|
6
|
+
REPO_ROOT="$HOME/code/machineconfig"
|
|
7
|
+
CONTEXT_PATH="$REPO_ROOT/.ai/todo/files.md"
|
|
8
|
+
# agents make-todo --strategy keywords from machineconfig.utils.path_extended import PathExtended
|
|
9
|
+
PROMPT_PATH="$REPO_ROOT/src/machineconfig/scripts/python/helpers_agents/templates/prompt.txt"
|
|
10
|
+
AGENTS_DIR="$REPO_ROOT/.ai/agents/$JOB_NAME"
|
|
11
|
+
|
|
12
|
+
agents create --agents crush \
|
|
13
|
+
--host docker \
|
|
14
|
+
--model x-ai/grok-4-fast:free \
|
|
15
|
+
--provider openrouter \
|
|
16
|
+
--context-path $CONTEXT_PATH \
|
|
17
|
+
--prompt-path $PROMPT_PATH \
|
|
18
|
+
--job-name $JOB_NAME \
|
|
19
|
+
--agents-dir $AGENTS_DIR
|
|
20
|
+
sessions balance-load "$AGENTS_DIR/layout.json" --max-thresh 6 --breaking-method moreLayouts --thresh-type number --output-path "$AGENTS_DIR/layout_balanced.json"
|
|
21
|
+
sessions run "$AGENTS_DIR/layout_balanced.json" --kill-upon-completion
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# agents collect $AGENTS_DIR "$REPO_ROOT/.ai/agents/$JOB_NAME/collected.txt"
|
|
@@ -46,7 +46,7 @@ def path():
|
|
|
46
46
|
uv_with = ["textual"]
|
|
47
47
|
uv_project_dir = None
|
|
48
48
|
if not Path.home().joinpath("code/machineconfig").exists():
|
|
49
|
-
uv_with.append("machineconfig>=6.
|
|
49
|
+
uv_with.append("machineconfig>=6.86")
|
|
50
50
|
else:
|
|
51
51
|
uv_project_dir = str(Path.home().joinpath("code/machineconfig"))
|
|
52
52
|
run_shell_script(get_uv_command_executing_python_script(python_script=path.read_text(encoding="utf-8"), uv_with=uv_with, uv_project_dir=uv_project_dir)[0])
|