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:
Federico Jaramillo Martinez
2026-06-16 14:53:37 +02:00
parent bfcd975c83
commit 95c151233a
26 changed files with 630 additions and 18 deletions
+16 -1
View File
@@ -2,7 +2,7 @@ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { DEFAULT_MAX_UPLOAD_BYTES, loadPiWebConfig, maxUploadBytes, savePiWebConfig } from "./config.js";
import { DEFAULT_MAX_UPLOAD_BYTES, loadPiWebConfig, maxUploadBytes, savePiWebConfig, spawnSessionsEnabled } from "./config.js";
let tempDir: string;
let configPath: string;
@@ -58,6 +58,21 @@ describe("maxUploadBytes", () => {
});
});
describe("spawnSessionsEnabled", () => {
it("is on by default when nothing is configured", () => {
expect(spawnSessionsEnabled({}, {})).toBe(true);
});
it("honors an explicit config opt-out", () => {
expect(spawnSessionsEnabled({}, { spawnSessions: false })).toBe(false);
});
it("lets the env var override the config in both directions", () => {
expect(spawnSessionsEnabled({ PI_WEB_SPAWN_SESSIONS: "0" }, { spawnSessions: true })).toBe(false);
expect(spawnSessionsEnabled({ PI_WEB_SPAWN_SESSIONS: "1" }, { spawnSessions: false })).toBe(true);
});
});
function testOptions(): { env: NodeJS.ProcessEnv } {
return { env: { PI_WEB_CONFIG: configPath } };
}