Merge 799829a8906a04d44ef9a0d6355a8214de5f34ae into 8a05c05596ca9ba0735dafd8e359885de4c2c969
This commit is contained in:
commit
076921f84c
@ -1525,3 +1525,241 @@ describe("loadCombinedSessionStoreForGateway includes disk-only agents (#32804)"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("listSessionsFromStore returns agent:main:main (#45754)", () => {
|
||||
test("both agent:main:main and channel sessions in same store are returned", () => {
|
||||
const cfg = {
|
||||
session: { mainKey: "main" },
|
||||
agents: { list: [{ id: "main", default: true }] },
|
||||
} as OpenClawConfig;
|
||||
|
||||
const store: Record<string, SessionEntry> = {
|
||||
"agent:main:main": {
|
||||
sessionId: "sess-main",
|
||||
updatedAt: Date.now(),
|
||||
} as SessionEntry,
|
||||
"agent:main:feishu:user123": {
|
||||
sessionId: "sess-feishu",
|
||||
updatedAt: Date.now() - 1000,
|
||||
} as SessionEntry,
|
||||
};
|
||||
|
||||
const result = listSessionsFromStore({
|
||||
cfg,
|
||||
storePath: "/tmp/sessions.json",
|
||||
store,
|
||||
opts: {},
|
||||
});
|
||||
|
||||
expect(result.sessions).toHaveLength(2);
|
||||
expect(result.sessions.map((s) => s.key)).toEqual(
|
||||
expect.arrayContaining(["agent:main:main", "agent:main:feishu:user123"]),
|
||||
);
|
||||
});
|
||||
|
||||
test("agent:main:main is returned when it is the only session", () => {
|
||||
const cfg = {
|
||||
session: { mainKey: "main" },
|
||||
agents: { list: [{ id: "main", default: true }] },
|
||||
} as OpenClawConfig;
|
||||
|
||||
const store: Record<string, SessionEntry> = {
|
||||
"agent:main:main": {
|
||||
sessionId: "sess-main",
|
||||
updatedAt: Date.now(),
|
||||
} as SessionEntry,
|
||||
};
|
||||
|
||||
const result = listSessionsFromStore({
|
||||
cfg,
|
||||
storePath: "/tmp/sessions.json",
|
||||
store,
|
||||
opts: {},
|
||||
});
|
||||
|
||||
expect(result.sessions).toHaveLength(1);
|
||||
expect(result.sessions[0]?.key).toBe("agent:main:main");
|
||||
});
|
||||
|
||||
test("agent:main:main returned via combined store with template path", async () => {
|
||||
await withStateDirEnv("openclaw-main-main-", async ({ stateDir }) => {
|
||||
const agentsDir = path.join(stateDir, "agents");
|
||||
const mainDir = path.join(agentsDir, "main", "sessions");
|
||||
fs.mkdirSync(mainDir, { recursive: true });
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(mainDir, "sessions.json"),
|
||||
JSON.stringify({
|
||||
"agent:main:main": { sessionId: "s-main", updatedAt: 100 },
|
||||
"agent:main:feishu:user123": { sessionId: "s-feishu", updatedAt: 200 },
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const cfg = {
|
||||
session: {
|
||||
mainKey: "main",
|
||||
store: path.join(stateDir, "agents", "{agentId}", "sessions", "sessions.json"),
|
||||
},
|
||||
agents: {
|
||||
list: [{ id: "main", default: true }],
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const { store } = loadCombinedSessionStoreForGateway(cfg);
|
||||
expect(store["agent:main:main"]).toBeDefined();
|
||||
expect(store["agent:main:feishu:user123"]).toBeDefined();
|
||||
|
||||
const result = listSessionsFromStore({
|
||||
cfg,
|
||||
storePath: path.join(mainDir, "sessions.json"),
|
||||
store,
|
||||
opts: {},
|
||||
});
|
||||
|
||||
expect(result.sessions).toHaveLength(2);
|
||||
expect(result.sessions.map((s) => s.key)).toEqual(
|
||||
expect.arrayContaining(["agent:main:main", "agent:main:feishu:user123"]),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("agent:main:main discovered when only other agents in agents.list", async () => {
|
||||
await withStateDirEnv("openclaw-main-discovered-", async ({ stateDir }) => {
|
||||
const agentsDir = path.join(stateDir, "agents");
|
||||
const mainDir = path.join(agentsDir, "main", "sessions");
|
||||
const feishuDir = path.join(agentsDir, "feishu", "sessions");
|
||||
fs.mkdirSync(mainDir, { recursive: true });
|
||||
fs.mkdirSync(feishuDir, { recursive: true });
|
||||
|
||||
// Main agent has sessions but is NOT in agents.list
|
||||
fs.writeFileSync(
|
||||
path.join(mainDir, "sessions.json"),
|
||||
JSON.stringify({
|
||||
"agent:main:main": { sessionId: "s-main", updatedAt: 100 },
|
||||
"agent:main:feishu:user123": { sessionId: "s-feishu", updatedAt: 200 },
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
// Empty store for feishu agent (which IS in agents.list)
|
||||
fs.writeFileSync(path.join(feishuDir, "sessions.json"), JSON.stringify({}), "utf8");
|
||||
|
||||
const cfg = {
|
||||
session: {
|
||||
mainKey: "main",
|
||||
store: path.join(stateDir, "agents", "{agentId}", "sessions", "sessions.json"),
|
||||
},
|
||||
agents: {
|
||||
// Only feishu is configured - main should be discovered from disk
|
||||
list: [{ id: "feishu", default: true }],
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const { store } = loadCombinedSessionStoreForGateway(cfg);
|
||||
|
||||
// Both sessions from the main agent's store should be discovered
|
||||
expect(store["agent:main:main"]).toBeDefined();
|
||||
expect(store["agent:main:feishu:user123"]).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
test("agent:main:main discovered with no agents.list configured", async () => {
|
||||
await withStateDirEnv("openclaw-no-agents-list-", async ({ stateDir }) => {
|
||||
const agentsDir = path.join(stateDir, "agents");
|
||||
const mainDir = path.join(agentsDir, "main", "sessions");
|
||||
fs.mkdirSync(mainDir, { recursive: true });
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(mainDir, "sessions.json"),
|
||||
JSON.stringify({
|
||||
"agent:main:main": { sessionId: "s-main", updatedAt: 100 },
|
||||
"agent:main:feishu:user123": { sessionId: "s-feishu", updatedAt: 200 },
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const cfg = {
|
||||
session: {
|
||||
mainKey: "main",
|
||||
store: path.join(stateDir, "agents", "{agentId}", "sessions", "sessions.json"),
|
||||
},
|
||||
// No agents.list - should use default "main" agent
|
||||
} as OpenClawConfig;
|
||||
|
||||
const { store } = loadCombinedSessionStoreForGateway(cfg);
|
||||
expect(store["agent:main:main"]).toBeDefined();
|
||||
expect(store["agent:main:feishu:user123"]).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
test("bare 'main' key in store is canonicalized to agent:main:main", async () => {
|
||||
await withStateDirEnv("openclaw-bare-main-", async ({ stateDir }) => {
|
||||
const agentsDir = path.join(stateDir, "agents");
|
||||
const mainDir = path.join(agentsDir, "main", "sessions");
|
||||
fs.mkdirSync(mainDir, { recursive: true });
|
||||
|
||||
// Store has bare "main" key (legacy format)
|
||||
fs.writeFileSync(
|
||||
path.join(mainDir, "sessions.json"),
|
||||
JSON.stringify({
|
||||
main: { sessionId: "s-main", updatedAt: 100 },
|
||||
"feishu:user123": { sessionId: "s-feishu", updatedAt: 200 },
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const cfg = {
|
||||
session: {
|
||||
mainKey: "main",
|
||||
store: path.join(stateDir, "agents", "{agentId}", "sessions", "sessions.json"),
|
||||
},
|
||||
agents: {
|
||||
list: [{ id: "main", default: true }],
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const { store } = loadCombinedSessionStoreForGateway(cfg);
|
||||
|
||||
// Bare keys should be canonicalized to agent-prefixed form
|
||||
expect(store["agent:main:main"]).toBeDefined();
|
||||
expect(store["agent:main:feishu:user123"]).toBeDefined();
|
||||
|
||||
const result = listSessionsFromStore({
|
||||
cfg,
|
||||
storePath: path.join(mainDir, "sessions.json"),
|
||||
store,
|
||||
opts: {},
|
||||
});
|
||||
|
||||
expect(result.sessions).toHaveLength(2);
|
||||
expect(result.sessions.map((s) => s.key)).toEqual(
|
||||
expect.arrayContaining(["agent:main:main", "agent:main:feishu:user123"]),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("agent:main:main included when sessions.json does not exist yet", async () => {
|
||||
await withStateDirEnv("openclaw-no-store-file-", async ({ stateDir }) => {
|
||||
const agentsDir = path.join(stateDir, "agents");
|
||||
const mainDir = path.join(agentsDir, "main", "sessions");
|
||||
// Create directory structure but do NOT create sessions.json
|
||||
fs.mkdirSync(mainDir, { recursive: true });
|
||||
|
||||
const cfg = {
|
||||
session: {
|
||||
mainKey: "main",
|
||||
store: path.join(stateDir, "agents", "{agentId}", "sessions", "sessions.json"),
|
||||
},
|
||||
agents: {
|
||||
list: [{ id: "main", default: true }],
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const { store } = loadCombinedSessionStoreForGateway(cfg);
|
||||
|
||||
// agent:main:main must be present even when store file does not exist
|
||||
expect(store["agent:main:main"]).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -865,6 +865,7 @@ export function loadCombinedSessionStoreForGateway(cfg: OpenClawConfig): {
|
||||
canonicalKey,
|
||||
});
|
||||
}
|
||||
ensureMainSessionKey(cfg, combined);
|
||||
return { storePath, store: combined };
|
||||
}
|
||||
|
||||
@ -886,6 +887,8 @@ export function loadCombinedSessionStoreForGateway(cfg: OpenClawConfig): {
|
||||
}
|
||||
}
|
||||
|
||||
ensureMainSessionKey(cfg, combined);
|
||||
|
||||
const storePath =
|
||||
typeof storeConfig === "string" && storeConfig.trim() ? storeConfig.trim() : "(multiple)";
|
||||
return { storePath, store: combined };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user