Skip to content

Commit 574894d

Browse files
committed
feat: persist python venv commands
1 parent 00be542 commit 574894d

3 files changed

Lines changed: 49 additions & 1 deletion

File tree

docs/CUSTOM_IMAGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export WAGGLE_RUNTIME_NODE_INSTALL_COMMAND="/usr/local/bin/npm install -g"
4545
- If `execute` fails, verify the runtime binary exists at the resolved path.
4646
- If `list_files` is empty or errors, confirm `find -printf` is available.
4747
- For Python, `install_packages` will retry in a venv when PEP 668 blocks system installs.
48+
Subsequent `execute` calls will use the venv interpreter automatically.
4849

4950
## Capabilities Data
5051
Waggle probes runtime capabilities (available binaries, package managers) to improve command resolution. This data is internal and not exposed over MCP by default. If we ever add an API for it, it will be redacted and opt-in to avoid leaking environment details.

pkg/service/execution.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const (
2828
defaultShellInstall = "apk add --no-cache"
2929
defaultPythonVenv = "/home/sandbox/venv"
3030
defaultPythonFallback = "/usr/bin/python3"
31+
defaultPythonVenvExec = "/home/sandbox/venv/bin/python"
32+
defaultPythonVenvPip = "/home/sandbox/venv/bin/pip"
3133
)
3234

3335
// ExecutionService orchestrates code execution within environments.
@@ -251,10 +253,14 @@ func (s *ExecutionService) retryPythonInstallInVenv(
251253
return venvResult, nil
252254
}
253255

256+
if updateErr := s.persistPythonVenvCommands(ctx, env.ID); updateErr != nil {
257+
slog.Warn("failed to persist python venv commands", "env_id", env.ID, "error", updateErr)
258+
}
259+
254260
venvInstall := &execution.PackageInstallation{
255261
Language: env.Runtime.String(),
256262
Packages: packages,
257-
InstallCommand: fmt.Sprintf("%s/bin/pip install", defaultPythonVenv),
263+
InstallCommand: fmt.Sprintf("%s install", defaultPythonVenvPip),
258264
}
259265

260266
return s.executor.InstallPackages(ctx, env.ID, conn, venvInstall)
@@ -289,6 +295,18 @@ func (s *ExecutionService) createPythonVenv(
289295
})
290296
}
291297

298+
func (s *ExecutionService) persistPythonVenvCommands(ctx context.Context, envID string) error {
299+
env, err := s.repo.FindByID(ctx, envID)
300+
if err != nil {
301+
return err
302+
}
303+
env.Capabilities.PythonCommand = defaultPythonVenvExec
304+
env.Capabilities.PipCommand = defaultPythonVenvPip
305+
env.Capabilities.DetectedAt = time.Now()
306+
env.CapabilitiesDetected = true
307+
return s.repo.Save(ctx, env)
308+
}
309+
292310
func isPep668(result *execution.ExecResult) bool {
293311
if result == nil || result.ExitCode == 0 {
294312
return false

pkg/service/execution_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,35 @@ func TestExecutionServiceInstallPackagesPep668FallbackUsesExplicitPython(t *test
257257
}
258258
}
259259

260+
func TestExecutionServiceInstallPackagesPersistsVenvCommands(t *testing.T) {
261+
t.Parallel()
262+
ctx := context.Background()
263+
264+
svc, executor, envID := setupExecTest(t)
265+
executor.pkgResults = []*execution.ExecResult{
266+
{ExitCode: 1, Stderr: "error: externally-managed-environment"},
267+
{ExitCode: 0},
268+
}
269+
executor.codeResults = []*execution.ExecResult{{ExitCode: 0}}
270+
271+
_, err := svc.InstallPackages(ctx, envID, []string{"numpy"})
272+
if err != nil {
273+
t.Fatalf("InstallPackages: %v", err)
274+
}
275+
276+
_, err = svc.Execute(ctx, envID, "print('ok')", "", 0)
277+
if err != nil {
278+
t.Fatalf("Execute: %v", err)
279+
}
280+
281+
if executor.lastCodeReq == nil {
282+
t.Fatal("ExecuteCode was not called")
283+
}
284+
if executor.lastCodeReq.ExecCommand != defaultPythonVenvExec {
285+
t.Errorf("ExecCommand = %q, want %q", executor.lastCodeReq.ExecCommand, defaultPythonVenvExec)
286+
}
287+
}
288+
260289
func TestExecutionServiceInstallPackagesNoPepFallback(t *testing.T) {
261290
t.Parallel()
262291
ctx := context.Background()

0 commit comments

Comments
 (0)