mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-21 05:54:59 +00:00
CLI: include agentId in aggregated sessions output
This commit is contained in:
@@ -24,6 +24,27 @@ Scope selection:
|
||||
- `--all-agents`: aggregate all configured agent stores
|
||||
- `--store <path>`: explicit store path (cannot be combined with `--agent` or `--all-agents`)
|
||||
|
||||
JSON examples:
|
||||
|
||||
`openclaw sessions --all-agents --json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"path": null,
|
||||
"stores": [
|
||||
{ "agentId": "main", "path": "/home/user/.openclaw/agents/main/sessions/sessions.json" },
|
||||
{ "agentId": "work", "path": "/home/user/.openclaw/agents/work/sessions/sessions.json" }
|
||||
],
|
||||
"allAgents": true,
|
||||
"count": 2,
|
||||
"activeMinutes": null,
|
||||
"sessions": [
|
||||
{ "agentId": "main", "key": "agent:main:main", "model": "gpt-5" },
|
||||
{ "agentId": "work", "key": "agent:work:main", "model": "claude-opus-4-5" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Cleanup maintenance
|
||||
|
||||
Run maintenance now (instead of waiting for the next write cycle):
|
||||
@@ -48,6 +69,34 @@ openclaw sessions cleanup --json
|
||||
- `--store <path>`: run against a specific `sessions.json` file.
|
||||
- `--json`: print a JSON summary. With `--all-agents`, output includes one summary per store.
|
||||
|
||||
`openclaw sessions cleanup --all-agents --dry-run --json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"allAgents": true,
|
||||
"mode": "warn",
|
||||
"dryRun": true,
|
||||
"stores": [
|
||||
{
|
||||
"agentId": "main",
|
||||
"storePath": "/home/user/.openclaw/agents/main/sessions/sessions.json",
|
||||
"beforeCount": 120,
|
||||
"afterCount": 80,
|
||||
"pruned": 40,
|
||||
"capped": 0
|
||||
},
|
||||
{
|
||||
"agentId": "work",
|
||||
"storePath": "/home/user/.openclaw/agents/work/sessions/sessions.json",
|
||||
"beforeCount": 18,
|
||||
"afterCount": 18,
|
||||
"pruned": 0,
|
||||
"capped": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Related:
|
||||
|
||||
- Session config: [Configuration reference](/gateway/configuration-reference#session)
|
||||
|
||||
@@ -25,6 +25,7 @@ const resolveStorePathMock = vi.hoisted(() =>
|
||||
return `/tmp/sessions-${opts?.agentId ?? "missing"}.json`;
|
||||
}),
|
||||
);
|
||||
const loadSessionStoreMock = vi.hoisted(() => vi.fn(() => ({})));
|
||||
|
||||
vi.mock("../config/config.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../config/config.js")>();
|
||||
@@ -39,7 +40,7 @@ vi.mock("../config/sessions.js", async (importOriginal) => {
|
||||
return {
|
||||
...actual,
|
||||
resolveStorePath: resolveStorePathMock,
|
||||
loadSessionStore: vi.fn(() => ({})),
|
||||
loadSessionStore: loadSessionStoreMock,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -58,6 +59,29 @@ function createRuntime(): { runtime: RuntimeEnv; logs: string[] } {
|
||||
}
|
||||
|
||||
describe("sessionsCommand default store agent selection", () => {
|
||||
it("includes agentId on sessions rows for --all-agents JSON output", async () => {
|
||||
resolveStorePathMock.mockClear();
|
||||
loadSessionStoreMock.mockReset();
|
||||
loadSessionStoreMock
|
||||
.mockReturnValueOnce({
|
||||
main_row: { sessionId: "s1", updatedAt: Date.now() - 60_000, model: "pi:opus" },
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
voice_row: { sessionId: "s2", updatedAt: Date.now() - 120_000, model: "pi:opus" },
|
||||
});
|
||||
const { runtime, logs } = createRuntime();
|
||||
|
||||
await sessionsCommand({ allAgents: true, json: true }, runtime);
|
||||
|
||||
const payload = JSON.parse(logs[0] ?? "{}") as {
|
||||
allAgents?: boolean;
|
||||
sessions?: Array<{ key: string; agentId?: string }>;
|
||||
};
|
||||
expect(payload.allAgents).toBe(true);
|
||||
expect(payload.sessions?.map((session) => session.agentId)).toContain("main");
|
||||
expect(payload.sessions?.map((session) => session.agentId)).toContain("voice");
|
||||
});
|
||||
|
||||
it("uses configured default agent id when resolving implicit session store path", async () => {
|
||||
resolveStorePathMock.mockClear();
|
||||
const { runtime, logs } = createRuntime();
|
||||
@@ -72,6 +96,12 @@ describe("sessionsCommand default store agent selection", () => {
|
||||
|
||||
it("uses all configured agent stores with --all-agents", async () => {
|
||||
resolveStorePathMock.mockClear();
|
||||
loadSessionStoreMock.mockReset();
|
||||
loadSessionStoreMock
|
||||
.mockReturnValueOnce({
|
||||
main_row: { sessionId: "s1", updatedAt: Date.now() - 60_000, model: "pi:opus" },
|
||||
})
|
||||
.mockReturnValueOnce({});
|
||||
const { runtime, logs } = createRuntime();
|
||||
|
||||
await sessionsCommand({ allAgents: true }, runtime);
|
||||
@@ -83,5 +113,6 @@ describe("sessionsCommand default store agent selection", () => {
|
||||
agentId: "voice",
|
||||
});
|
||||
expect(logs[0]).toContain("Session stores: 2 (main, voice)");
|
||||
expect(logs[2]).toContain("Agent");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,9 +22,11 @@ import {
|
||||
} from "./sessions-table.js";
|
||||
|
||||
type SessionRow = SessionDisplayRow & {
|
||||
agentId: string;
|
||||
kind: "direct" | "group" | "global" | "unknown";
|
||||
};
|
||||
|
||||
const AGENT_PAD = 10;
|
||||
const KIND_PAD = 6;
|
||||
const TOKENS_PAD = 20;
|
||||
|
||||
@@ -120,6 +122,7 @@ export async function sessionsCommand(
|
||||
const store = loadSessionStore(target.storePath);
|
||||
return toSessionDisplayRows(store).map((row) => ({
|
||||
...row,
|
||||
agentId: target.agentId,
|
||||
kind: classifySessionKey(row.key, store[row.key]),
|
||||
}));
|
||||
})
|
||||
@@ -186,7 +189,9 @@ export async function sessionsCommand(
|
||||
}
|
||||
|
||||
const rich = isRich();
|
||||
const showAgentColumn = targets.length > 1;
|
||||
const header = [
|
||||
...(showAgentColumn ? ["Agent".padEnd(AGENT_PAD)] : []),
|
||||
"Kind".padEnd(KIND_PAD),
|
||||
"Key".padEnd(SESSION_KEY_PAD),
|
||||
"Age".padEnd(SESSION_AGE_PAD),
|
||||
@@ -203,6 +208,9 @@ export async function sessionsCommand(
|
||||
const total = resolveFreshSessionTotalTokens(row);
|
||||
|
||||
const line = [
|
||||
...(showAgentColumn
|
||||
? [rich ? theme.accentBright(row.agentId.padEnd(AGENT_PAD)) : row.agentId.padEnd(AGENT_PAD)]
|
||||
: []),
|
||||
formatKindCell(row.kind, rich),
|
||||
formatSessionKeyCell(row.key, rich),
|
||||
formatSessionAgeCell(row.updatedAt, rich),
|
||||
|
||||
Reference in New Issue
Block a user