Merge PR #7783: fix(acp): resolve session/load across legacy session directories (@roboomp)

This commit is contained in:
can1357
2026-08-07 13:39:53 +02:00
3 changed files with 56 additions and 1 deletions
+4
View File
@@ -99,6 +99,10 @@
- Fixed a per-turn `before_agent_start` system prompt override being silently dropped when a base-prompt rebuild fired between the hook and the provider request. The override lived only on the agent state, so `refreshBaseSystemPrompt`/`applyActiveToolsByName` re-pushing the rebuilt base (context-overflow compaction/promotion, memory promotion, MCP/RPC tool refresh, or the fire-and-forget hindsight MM-TTL refresh) clobbered it. The tools controller now tracks the active override and re-applies it on every base rebuild during the turn, clearing it when the turn ends ([#7755](https://github.com/can1357/oh-my-pi/issues/7755)).
### Fixed
- Fixed ACP `session/load` and `session/resume` failing with `ACP session not found` for sessions created under the legacy/hashed project-directory scheme (17.2.5+, reverted in #7656): the lookup only scanned the directory re-derived from `cwd`, so sessions stored under a differently-named directory were unreachable. It now falls back to a global by-id scan (the same one the fork path already uses) when the cwd-scoped lookup misses ([#7779](https://github.com/can1357/oh-my-pi/issues/7779)).
## [17.2.9] - 2026-08-05
### Breaking Changes
@@ -2019,7 +2019,16 @@ export class AcpAgent implements Agent {
async #findStoredSession(sessionId: string, cwd: string): Promise<StoredSessionInfo | undefined> {
const sessions = await this.#listStoredSessions(cwd);
return sessions.find(session => session.id === sessionId);
const scoped = sessions.find(session => session.id === sessionId);
if (scoped) {
return scoped;
}
// The cwd-derived directory only covers sessions stored under the current
// naming scheme. Sessions written under a legacy/hashed project directory
// (the 17.2.5+ scheme reverted in #7656) live elsewhere, so fall back to a
// global by-id scan: the session id is globally unique, and
// #openStoredSession reopens the file with the request cwd. See #7779.
return this.#findStoredSessionById(sessionId);
}
async #findStoredSessionById(sessionId: string): Promise<StoredSessionInfo | undefined> {
@@ -1098,6 +1098,48 @@ describe("ACP agent", () => {
await Bun.sleep(0);
});
it("loads a session stored under a legacy/hashed project directory (#7779)", async () => {
const harness = await createHarness();
const stored = new FakeAgentSession(harness.cwdA);
harness.sessions.push(stored);
stored.sessionManager.appendMessage({ role: "user", content: "legacy hello", timestamp: Date.now() });
stored.sessionManager.appendMessage(makeAssistantMessage("legacy reply"));
await stored.sessionManager.ensureOnDisk();
await stored.sessionManager.flush();
const sessionFile = stored.sessionManager.getSessionFile();
if (!sessionFile) throw new Error("session file not persisted");
const sessionId = stored.sessionId;
// Release the writer so the directory can be renamed out from under it.
await stored.dispose();
// Simulate the hashed-directory era (#7397, reverted in #7656): the
// session file lives under a project directory whose name the current
// cwd->dir scheme would never produce, so the cwd-scoped scan misses it.
const cwdDerivedDir = path.dirname(sessionFile);
const sessionsRoot = path.dirname(cwdDerivedDir);
const hashedDir = path.join(sessionsRoot, `home-cwd-a-${"a".repeat(64)}`);
await fs.promises.rename(cwdDerivedDir, hashedDir);
const loaded = await harness.agent.loadSession({
sessionId,
cwd: harness.cwdA,
mcpServers: [],
});
expectAcpStructure(zLoadSessionResponse, loaded);
const replayChunks = harness.updates.filter(
update =>
update.sessionId === sessionId &&
(update.update.sessionUpdate === "user_message_chunk" ||
update.update.sessionUpdate === "agent_message_chunk"),
);
expect(replayChunks.length).toBeGreaterThan(0);
harness.abortController.abort();
await Bun.sleep(0);
});
it("delivers the final visible answer when agent_end overtakes the assistant message_end (#4902)", async () => {
const harness = await createHarness();
const created = await harness.agent.newSession({ cwd: harness.cwdA, mcpServers: [] });