feat(subagent): default subagent dispatch to swarm in code, not just wrapper
The bash wrapper bin/sf-from-source exports SF_SUBAGENT_VIA_SWARM=1 to make the swarm/messagebus path the default for subagent dispatch. That covers every sf launch via the wrapper but does NOT cover the web-launched sf — src/web/cli-entry.ts:resolveSfCliEntry spawns sf by calling process.execPath (node) directly with src/loader.ts or dist/loader.js, bypassing the wrapper entirely. So /tmp/sf-web- onboarding-runtime-* sf processes were still falling through to the direct-runSubagent subprocess path. Flip the default in code instead: swarm runs unless SF_SUBAGENT_VIA_SWARM is explicitly set to "0" or "false". Now every sf launch — wrapper, web, dev-cli, packaged-standalone — picks up the same default. The wrapper's export line is now redundant but harmless; keeping it as defense-in-depth (documents the intent at the wrapper layer too). Test update: subagent-via-swarm.test.mjs's "unset → subprocess" assertion is updated to "=0 → subprocess" — the unset case now means swarm-by-default. All 13 tests in that file pass. The other tests in the file that explicitly set the flag to "1"/"true" are unaffected. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9a84d82cdb
commit
bde55dfc87
2 changed files with 15 additions and 8 deletions
|
|
@ -1452,9 +1452,15 @@ async function runSingleAgent(
|
|||
};
|
||||
}
|
||||
}
|
||||
// Feature flag: route through swarm dispatch instead of direct runSubagent.
|
||||
// Subagent dispatch defaults to the swarm/messagebus path; the bash
|
||||
// wrapper bin/sf-from-source used to set SF_SUBAGENT_VIA_SWARM=1 for
|
||||
// that, but the web-launched sf goes node → src/loader.ts directly
|
||||
// and bypasses the wrapper, so the default is enforced in code here.
|
||||
// Opt out with SF_SUBAGENT_VIA_SWARM=0 (or =false) when running tests
|
||||
// or workflows that need the direct-runSubagent subprocess path.
|
||||
const swarmFlag = process.env.SF_SUBAGENT_VIA_SWARM;
|
||||
if (swarmFlag === "1" || swarmFlag === "true") {
|
||||
const swarmDisabled = swarmFlag === "0" || swarmFlag === "false";
|
||||
if (!swarmDisabled) {
|
||||
return runSingleAgentViaSwarm(
|
||||
defaultCwd,
|
||||
agent,
|
||||
|
|
|
|||
|
|
@ -84,11 +84,12 @@ afterEach(() => {
|
|||
|
||||
// ─── Tests ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
test("SF_SUBAGENT_VIA_SWARM unset → runSubagent path, swarmDispatchAndWait NOT called", async () => {
|
||||
// With the flag unset, runSingleAgent should NOT touch swarmDispatchAndWait.
|
||||
// It will try to call runSubagent (from @singularity-forge/coding-agent), which
|
||||
// will fail inside the test environment — we just need to confirm the swarm path
|
||||
// was NOT taken.
|
||||
test("SF_SUBAGENT_VIA_SWARM=0 → runSubagent path, swarmDispatchAndWait NOT called", async () => {
|
||||
// With the flag explicitly disabled, runSingleAgent should NOT touch
|
||||
// swarmDispatchAndWait. It will try to call runSubagent (from
|
||||
// @singularity-forge/coding-agent), which will fail inside the test
|
||||
// environment — we just need to confirm the swarm path was NOT taken.
|
||||
process.env.SF_SUBAGENT_VIA_SWARM = "0";
|
||||
const agents = makeAgents();
|
||||
|
||||
try {
|
||||
|
|
@ -115,7 +116,7 @@ test("SF_SUBAGENT_VIA_SWARM unset → runSubagent path, swarmDispatchAndWait NOT
|
|||
assert.equal(
|
||||
swarmDispatchAndWait.mock.calls.length,
|
||||
0,
|
||||
"swarmDispatchAndWait should not be called when flag is unset",
|
||||
"swarmDispatchAndWait should not be called when flag is explicitly disabled",
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue