4 Commits

Author SHA1 Message Date
tjb-tech 57a9134997 test(swarm): accept versioned Python executables 2026-05-06 10:05:11 +00:00
David Whatley 5f97b2416e fix(swarm,tasks): direct-exec teammate spawn, bypass shell on Windows (#230)
Teammate spawn (`agent` tool, `task_create`) failed on Windows with exit
127 and "command not found" against a backslash-mangled Python path,
even though the same `bash -lc "..."` command worked interactively.

Root cause: `subprocess_backend.spawn` built a single shell command
string with a `KEY='val' python ...` env-prefix, then routed through
`bash -lc` via `asyncio.create_subprocess_exec`. Two failures stacked:

  1. The env-prefix string used Python `repr()` for values, and Git
     Bash's `-lc` argument parser consumed backslashes inside the
     quoted segments as escape sequences (`\U` -> `U`).
  2. Even with proper `shlex.quote` of every command part — keeping
     backslashes intact — Git Bash launched via
     `asyncio.create_subprocess_exec` could not exec a Windows-pathed
     Python interpreter, returning `command not found` for the same
     argv that interactive bash exec'd fine.

Fix: don't use a shell at all for teammate spawn.

  * Add `argv: list[str] | None` to `TaskRecord` plus matching kwargs
    on `BackgroundTaskManager.create_shell_task` /
    `create_agent_task`. Either `command` (shell) or `argv` (direct
    exec) must be supplied; both is rejected.
  * `_start_process` runs the argv path via
    `asyncio.create_subprocess_exec(*argv, env=...)` directly, with no
    bash wrapper.
  * `subprocess_backend.spawn` builds an argv list (via
    `get_teammate_command()` plus inherited CLI flags) and hands it to
    `create_agent_task(argv=..., env=...)`. Inherited env vars now
    flow through `env=` rather than being embedded in the command
    string.
  * The legacy shell-evaluated `command=` path is preserved verbatim
    for callers (e.g. `BashTool`) that legitimately want shell
    semantics — only teammate spawn migrates to direct exec.

Tests: 5 new unit tests in `tests/test_swarm/test_subprocess_backend.py`
and 3 in `tests/test_tasks/test_manager.py` lock in the contract — env
plumbed via `env=` kwarg, argv list preserves Windows backslashed
paths, command/argv mutual exclusion, direct-exec round-trip.

Validated end-to-end on Windows 11 against a real CEO/Lead workflow:
CEO successfully calls `agent` tool, Lead spawns at depth=1 and
issues 29 tool calls. Same path was producing exit-127 task logs
before this change.
2026-05-04 16:21:40 -05:00
tjb-tech ee97f8e78d test(swarm): stabilize subprocess backend prompt coverage 2026-04-20 08:10:05 +00:00
tjb-tech 1158027082 fix(swarm): forward worker system prompts to subprocesses 2026-04-20 08:05:41 +00:00