mirror of
https://github.com/eggent-ai/eggent.git
synced 2026-05-13 15:46:00 +00:00
Improve Python package recovery with venv fallback
This commit is contained in:
@@ -391,13 +391,15 @@ function prepareExecution(params: {
|
||||
cwd: string;
|
||||
}): PreparedExecution {
|
||||
if (params.runtime === "python") {
|
||||
const pythonCommand = resolvePythonCommand(params.cwd);
|
||||
const pythonLabel = path.basename(pythonCommand) === "python3" ? "python3" : pythonCommand;
|
||||
return {
|
||||
runtime: "python",
|
||||
command: "python3",
|
||||
command: pythonCommand,
|
||||
args: ["-c", params.code],
|
||||
cwd: params.cwd,
|
||||
env: { ...process.env, PYTHONUNBUFFERED: "1" },
|
||||
commandPreview: `python3 -c ${previewText(params.code)}`,
|
||||
env: buildPythonEnv(params.cwd),
|
||||
commandPreview: `${pythonLabel} -c ${previewText(params.code)}`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -443,6 +445,50 @@ function prepareExecution(params: {
|
||||
};
|
||||
}
|
||||
|
||||
function buildPythonEnv(cwd: string): NodeJS.ProcessEnv {
|
||||
const env: NodeJS.ProcessEnv = { ...process.env, PYTHONUNBUFFERED: "1" };
|
||||
const venvDir = resolveProjectVenvDir(cwd);
|
||||
if (!venvDir) {
|
||||
return env;
|
||||
}
|
||||
|
||||
const currentPath = env.PATH || "";
|
||||
env.VIRTUAL_ENV = venvDir;
|
||||
env.PATH = [path.join(venvDir, "bin"), currentPath].filter(Boolean).join(path.delimiter);
|
||||
return env;
|
||||
}
|
||||
|
||||
function resolvePythonCommand(cwd: string): string {
|
||||
const venvPython = resolveProjectVenvPython(cwd);
|
||||
if (venvPython) {
|
||||
return venvPython;
|
||||
}
|
||||
|
||||
return "python3";
|
||||
}
|
||||
|
||||
function resolveProjectVenvDir(cwd: string): string | null {
|
||||
const candidates = [".venv", "venv"];
|
||||
for (const name of candidates) {
|
||||
const candidateDir = path.join(cwd, name);
|
||||
const candidatePython = path.join(candidateDir, "bin", "python");
|
||||
if (fs.existsSync(candidatePython)) {
|
||||
return candidateDir;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function resolveProjectVenvPython(cwd: string): string | null {
|
||||
const venvDir = resolveProjectVenvDir(cwd);
|
||||
if (!venvDir) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pythonBin = path.join(venvDir, "bin", "python");
|
||||
return fs.existsSync(pythonBin) ? pythonBin : null;
|
||||
}
|
||||
|
||||
function startManagedExecution(params: {
|
||||
prepared: PreparedExecution;
|
||||
timeoutMs: number;
|
||||
|
||||
@@ -234,6 +234,21 @@ function buildPythonPlans(params: {
|
||||
},
|
||||
],
|
||||
});
|
||||
plans.push({
|
||||
manager: "pip-venv",
|
||||
steps: [
|
||||
{
|
||||
manager: "pip-venv",
|
||||
argv: ["python3", "-m", "venv", ".venv"],
|
||||
cwd: params.cwd,
|
||||
},
|
||||
{
|
||||
manager: "pip-venv",
|
||||
argv: [path.join(".venv", "bin", "python"), "-m", "pip", "install", ...params.packages],
|
||||
cwd: params.cwd,
|
||||
},
|
||||
],
|
||||
});
|
||||
} else if (commandExists("python")) {
|
||||
plans.push({
|
||||
manager: "pip",
|
||||
@@ -245,6 +260,21 @@ function buildPythonPlans(params: {
|
||||
},
|
||||
],
|
||||
});
|
||||
plans.push({
|
||||
manager: "pip-venv",
|
||||
steps: [
|
||||
{
|
||||
manager: "pip-venv",
|
||||
argv: ["python", "-m", "venv", ".venv"],
|
||||
cwd: params.cwd,
|
||||
},
|
||||
{
|
||||
manager: "pip-venv",
|
||||
argv: [path.join(".venv", "bin", "python"), "-m", "pip", "install", ...params.packages],
|
||||
cwd: params.cwd,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
if (!uvPreferred && commandExists("uv")) {
|
||||
|
||||
@@ -25,7 +25,7 @@ You are a powerful AI agent with access to tools that allow you to interact with
|
||||
- Use the **code_execution** tool to run code
|
||||
- Choose the appropriate runtime: `python` for data processing and scripting, `nodejs` for web/JS tasks, `terminal` for shell commands
|
||||
- Always handle errors and edge cases in your code
|
||||
- If Python fails with `ModuleNotFoundError`, install the missing dependency with `python3 -m pip install <package>` using `terminal`, then retry
|
||||
- If Python fails with `ModuleNotFoundError`, install the missing dependency via `install_packages` (`kind=python`) and retry. If system pip is blocked (`externally-managed-environment`), use a project-local virtualenv (`python3 -m venv .venv`) and install there.
|
||||
- If Node.js fails with `Cannot find module '<name>'`, install the missing package via `install_packages` (`kind=node`) or the project's package manager, then retry once
|
||||
- For OS-level packages on Debian/Ubuntu, use `apt-get`/`apt` and add `sudo` only when needed and available
|
||||
- For file operations, prefer dedicated file tools (`read_text_file`, `read_pdf_file`, `write_text_file`, `copy_file`) over code execution
|
||||
|
||||
@@ -16,7 +16,7 @@ Execute code in a specified runtime environment. The code runs on the user's mac
|
||||
4. **Check prerequisites** — verify packages are installed before importing
|
||||
5. **Use sessions wisely** — session 0 is the default; reuse the same session to keep terminal working-directory state between calls
|
||||
6. **Prefer dedicated file tools first** — use `read_text_file`, `read_pdf_file`, `write_text_file`, and `copy_file` for common file tasks; use `code_execution` only when those tools are insufficient
|
||||
7. **Auto-resolve missing Python deps** — if you see `ModuleNotFoundError`, run `python3 -m pip install <package>` in `terminal`, then rerun Python code
|
||||
7. **Auto-resolve missing Python deps** — if you see `ModuleNotFoundError`, call `install_packages` with `kind=python` and retry. If pip reports `externally-managed-environment`, install into a project-local virtualenv (`python3 -m venv .venv` + `.venv/bin/python -m pip install <package>`).
|
||||
8. **Auto-resolve missing Node deps** — if you see `Cannot find module '<name>'`, install it via `install_packages` (`kind=node`, package `<name>`) or package manager command, then rerun Node code once
|
||||
9. **Install system packages carefully** — for Debian/Ubuntu, use `apt-get`/`apt`; add `sudo` only when required and available
|
||||
10. **Use background mode for long jobs** — set `background=true` or `yield_ms` and then use the `process` tool to poll/log/kill
|
||||
@@ -43,7 +43,7 @@ Do not stop after first failure for these classes:
|
||||
## Examples
|
||||
|
||||
### Install a package then use it
|
||||
First execution: `python3 -m pip install requests` (runtime: terminal)
|
||||
First execution: `install_packages(kind="python", packages=["requests"])`
|
||||
Second execution: `import requests; r = requests.get('...'); print(r.json())` (runtime: python)
|
||||
|
||||
### Install a system package
|
||||
|
||||
Reference in New Issue
Block a user