diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 2aaa98a1..90ce4736 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixed - Fixed `ctrl+z` suspend and `fg` resume reliability by keeping the process alive until the `SIGCONT` handler restores the TUI, avoiding immediate process exit in environments with no other live event-loop handles ([#2454](https://github.com/badlogic/pi-mono/issues/2454)) +- Fixed `createAgentSession({ agentDir })` to derive the default persisted session path from the provided `agentDir`, keeping session storage aligned with settings, auth, models, and resource loading ([#2457](https://github.com/badlogic/pi-mono/issues/2457)) ## [0.61.0] - 2026-03-20 diff --git a/packages/coding-agent/src/core/sdk.ts b/packages/coding-agent/src/core/sdk.ts index 7ef0ac7f..a67ab3f3 100644 --- a/packages/coding-agent/src/core/sdk.ts +++ b/packages/coding-agent/src/core/sdk.ts @@ -11,7 +11,7 @@ import { ModelRegistry } from "./model-registry.js"; import { findInitialModel } from "./model-resolver.js"; import type { ResourceLoader } from "./resource-loader.js"; import { DefaultResourceLoader } from "./resource-loader.js"; -import { SessionManager } from "./session-manager.js"; +import { getDefaultSessionDir, SessionManager } from "./session-manager.js"; import { SettingsManager } from "./settings-manager.js"; import { time } from "./timings.js"; import { @@ -176,7 +176,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} const modelRegistry = options.modelRegistry ?? new ModelRegistry(authStorage, modelsPath); const settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir); - const sessionManager = options.sessionManager ?? SessionManager.create(cwd); + const sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir)); if (!resourceLoader) { resourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager }); diff --git a/packages/coding-agent/src/core/session-manager.ts b/packages/coding-agent/src/core/session-manager.ts index e22a2e0a..1f908e46 100644 --- a/packages/coding-agent/src/core/session-manager.ts +++ b/packages/coding-agent/src/core/session-manager.ts @@ -418,9 +418,9 @@ export function buildSessionContext( * Compute the default session directory for a cwd. * Encodes cwd into a safe directory name under ~/.pi/agent/sessions/. */ -function getDefaultSessionDir(cwd: string): string { +export function getDefaultSessionDir(cwd: string, agentDir: string = getDefaultAgentDir()): string { const safePath = `--${cwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`; - const sessionDir = join(getDefaultAgentDir(), "sessions", safePath); + const sessionDir = join(agentDir, "sessions", safePath); if (!existsSync(sessionDir)) { mkdirSync(sessionDir, { recursive: true }); } diff --git a/packages/coding-agent/test/sdk-session-manager.test.ts b/packages/coding-agent/test/sdk-session-manager.test.ts new file mode 100644 index 00000000..554660b5 --- /dev/null +++ b/packages/coding-agent/test/sdk-session-manager.test.ts @@ -0,0 +1,66 @@ +import { existsSync, mkdirSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { getModel } from "@mariozechner/pi-ai"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { createAgentSession } from "../src/core/sdk.js"; +import { SessionManager } from "../src/core/session-manager.js"; + +describe("createAgentSession session manager defaults", () => { + let tempDir: string; + let cwd: string; + let agentDir: string; + + beforeEach(() => { + tempDir = join(tmpdir(), `pi-sdk-session-test-${Date.now()}-${Math.random().toString(36).slice(2)}`); + cwd = join(tempDir, "project"); + agentDir = join(tempDir, "agent"); + mkdirSync(cwd, { recursive: true }); + mkdirSync(agentDir, { recursive: true }); + }); + + afterEach(() => { + if (tempDir && existsSync(tempDir)) { + rmSync(tempDir, { recursive: true, force: true }); + } + }); + + it("uses agentDir for the default persisted session path", async () => { + const model = getModel("anthropic", "claude-sonnet-4-5"); + expect(model).toBeTruthy(); + + const { session } = await createAgentSession({ + cwd, + agentDir, + model: model!, + }); + + const safePath = `--${cwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`; + const expectedSessionDir = join(agentDir, "sessions", safePath); + const sessionDir = session.sessionManager.getSessionDir(); + const sessionFile = session.sessionManager.getSessionFile(); + + expect(sessionDir).toBe(expectedSessionDir); + expect(sessionFile?.startsWith(`${expectedSessionDir}/`)).toBe(true); + + session.dispose(); + }); + + it("keeps an explicit sessionManager override", async () => { + const model = getModel("anthropic", "claude-sonnet-4-5"); + expect(model).toBeTruthy(); + + const sessionManager = SessionManager.inMemory(cwd); + const { session } = await createAgentSession({ + cwd, + agentDir, + model: model!, + sessionManager, + }); + + expect(session.sessionManager).toBe(sessionManager); + expect(session.sessionManager.isPersisted()).toBe(false); + + session.dispose(); + }); +});