Archived
feat: let agents start new sessions via spawn_session tool
Add a project-scoped spawn_session tool so agents can dispatch new, independent sessions (ralph loops, long-plan chaining). Spawned sessions are constrained to a workspace/worktree of the same registered project, appear in the session list immediately via a new session.created event, and the capability is on by default with a Settings -> Session daemon toggle (spawnSessions / PI_WEB_SPAWN_SESSIONS). Note: adds a session daemon code path, so pi-web-sessiond.service must be restarted manually for the server side to take effect.
This commit is contained in:
@@ -82,6 +82,9 @@ export function effectivePiWebConfig(options: LoadOptions = {}): LoadedPiWebConf
|
||||
...(port !== undefined && port !== "" ? { port: parsePort(port, "PI_WEB_PORT") } : {}),
|
||||
...(allowedHosts !== undefined && allowedHosts !== "" ? { allowedHosts: parseAllowedHostsEnv(allowedHosts) } : {}),
|
||||
...(maxUpload !== undefined && maxUpload !== "" ? { maxUploadBytes: parseMaxUploadBytes(maxUpload, "PI_WEB_MAX_UPLOAD_BYTES") } : {}),
|
||||
// Always resolved (on by default) so the effective config is the single
|
||||
// source of truth for the runtime state and the settings UI toggle.
|
||||
spawnSessions: spawnSessionsEnabled(env, loaded.config),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -97,6 +100,7 @@ export function savePiWebConfig(config: PiWebConfig, options: LoadOptions = {}):
|
||||
delete existing["shortcuts"];
|
||||
delete existing["plugins"];
|
||||
delete existing["maxUploadBytes"];
|
||||
delete existing["spawnSessions"];
|
||||
const merged = { ...existing, ...piWebConfigRecord(normalized) };
|
||||
mkdirSync(dirname(path), { recursive: true });
|
||||
writeFileSync(path, `${JSON.stringify(merged, null, 2)}\n`, "utf8");
|
||||
@@ -118,6 +122,7 @@ function piWebConfigRecord(config: PiWebConfig): Record<string, unknown> {
|
||||
...(config.shortcuts !== undefined ? { shortcuts: config.shortcuts } : {}),
|
||||
...(config.plugins !== undefined ? { plugins: config.plugins } : {}),
|
||||
...(config.maxUploadBytes !== undefined ? { maxUploadBytes: config.maxUploadBytes } : {}),
|
||||
...(config.spawnSessions !== undefined ? { spawnSessions: config.spawnSessions } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -129,6 +134,7 @@ function parsePiWebConfig(value: Record<string, unknown>, path: string): PiWebCo
|
||||
...(value["shortcuts"] !== undefined ? { shortcuts: parseShortcuts(value["shortcuts"], path) } : {}),
|
||||
...(value["plugins"] !== undefined ? { plugins: parsePlugins(value["plugins"], path) } : {}),
|
||||
...(value["maxUploadBytes"] !== undefined ? { maxUploadBytes: parseMaxUploadBytes(value["maxUploadBytes"], "maxUploadBytes", path) } : {}),
|
||||
...(value["spawnSessions"] !== undefined ? { spawnSessions: parseSpawnSessions(value["spawnSessions"], path) } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -138,6 +144,23 @@ function parseMaxUploadBytes(value: unknown, key: string, path = "environment"):
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function parseSpawnSessions(value: unknown, path: string): boolean {
|
||||
if (typeof value !== "boolean") throw new Error(`PI WEB config spawnSessions must be a boolean: ${path}`);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether LLMs may start new sessions via the spawn_session tool. On by default
|
||||
* (spawned sessions appear in the session list, so humans notice them); set the
|
||||
* env var `PI_WEB_SPAWN_SESSIONS` or the `spawnSessions` config key to `false`
|
||||
* to disable. The env var takes precedence over the config file.
|
||||
*/
|
||||
export function spawnSessionsEnabled(env: NodeJS.ProcessEnv = process.env, config: PiWebConfig = {}): boolean {
|
||||
const fromEnv = env["PI_WEB_SPAWN_SESSIONS"];
|
||||
if (fromEnv !== undefined && fromEnv !== "") return fromEnv === "1" || fromEnv.toLowerCase() === "true";
|
||||
return config.spawnSessions ?? true;
|
||||
}
|
||||
|
||||
function parseString(value: unknown, key: string, path: string): string {
|
||||
if (typeof value !== "string" || value === "") throw new Error(`PI WEB config ${key} must be a non-empty string: ${path}`);
|
||||
return value;
|
||||
|
||||
Reference in New Issue
Block a user