mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:00:43 +00:00
fix(agents): filter session previews after visibility
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ChannelMessagingAdapter } from "../channels/plugins/types.js";
|
||||
@@ -297,9 +299,7 @@ describe("sessions tools", () => {
|
||||
params: {
|
||||
activeMinutes: undefined,
|
||||
agentId: "main",
|
||||
includeDerivedTitles: true,
|
||||
includeGlobal: true,
|
||||
includeLastMessage: true,
|
||||
includeUnknown: true,
|
||||
label: "mailbox",
|
||||
limit: undefined,
|
||||
@@ -356,6 +356,93 @@ describe("sessions tools", () => {
|
||||
expect(cronDetails.sessions?.[0]?.kind).toBe("cron");
|
||||
});
|
||||
|
||||
it("derives mailbox previews only after agent visibility filtering", async () => {
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-sessions-list-preview-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
try {
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, "visible.jsonl"),
|
||||
[
|
||||
JSON.stringify({ type: "session", id: "visible" }),
|
||||
JSON.stringify({ message: { role: "user", content: "Visible project kickoff" } }),
|
||||
JSON.stringify({ message: { role: "assistant", content: "Visible latest reply" } }),
|
||||
].join("\n"),
|
||||
"utf-8",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, "hidden.jsonl"),
|
||||
[
|
||||
JSON.stringify({ type: "session", id: "hidden" }),
|
||||
JSON.stringify({ message: { role: "user", content: "Hidden cross-agent topic" } }),
|
||||
JSON.stringify({ message: { role: "assistant", content: "Hidden latest reply" } }),
|
||||
].join("\n"),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
callGatewayMock.mockImplementation(async (opts: unknown) => {
|
||||
const request = opts as { method?: string; params?: Record<string, unknown> };
|
||||
if (request.method === "sessions.list") {
|
||||
expect(request.params?.includeDerivedTitles).toBeUndefined();
|
||||
expect(request.params?.includeLastMessage).toBeUndefined();
|
||||
return {
|
||||
path: storePath,
|
||||
sessions: [
|
||||
{
|
||||
key: "agent:main:main",
|
||||
kind: "direct",
|
||||
sessionId: "visible",
|
||||
updatedAt: 20,
|
||||
},
|
||||
{
|
||||
key: "agent:other:main",
|
||||
kind: "direct",
|
||||
sessionId: "hidden",
|
||||
updatedAt: 21,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
return {};
|
||||
});
|
||||
|
||||
const tool = createOpenClawTools({
|
||||
agentSessionKey: "agent:main:main",
|
||||
config: {
|
||||
...TEST_CONFIG,
|
||||
tools: {
|
||||
sessions: { visibility: "agent" },
|
||||
agentToAgent: { enabled: false },
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
}).find((candidate) => candidate.name === "sessions_list");
|
||||
expect(tool).toBeDefined();
|
||||
if (!tool) {
|
||||
throw new Error("missing sessions_list tool");
|
||||
}
|
||||
|
||||
const result = await tool.execute("call-preview", {
|
||||
includeDerivedTitles: true,
|
||||
includeLastMessage: true,
|
||||
});
|
||||
const details = result.details as {
|
||||
sessions?: Array<{
|
||||
key?: string;
|
||||
derivedTitle?: string;
|
||||
lastMessagePreview?: string;
|
||||
}>;
|
||||
};
|
||||
expect(details.sessions).toHaveLength(1);
|
||||
expect(details.sessions?.[0]).toMatchObject({
|
||||
key: "agent:main:main",
|
||||
derivedTitle: "Visible project kickoff",
|
||||
lastMessagePreview: "Visible latest reply",
|
||||
});
|
||||
expect(JSON.stringify(details.sessions)).not.toContain("Hidden");
|
||||
} finally {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("sessions_list resolves transcriptPath from agent state dir for multi-store listings", async () => {
|
||||
callGatewayMock.mockImplementation(async (opts: unknown) => {
|
||||
const request = opts as { method?: string };
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
} from "../../config/sessions.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { callGateway } from "../../gateway/call.js";
|
||||
import { readSessionTitleFieldsFromTranscript } from "../../gateway/session-utils.fs.js";
|
||||
import { deriveSessionTitle } from "../../gateway/session-utils.js";
|
||||
import { resolveAgentIdFromSessionKey } from "../../routing/session-key.js";
|
||||
import { normalizeOptionalLowercaseString, readStringValue } from "../../shared/string-coerce.js";
|
||||
import {
|
||||
@@ -105,8 +107,8 @@ export function createSessionsListTool(opts?: {
|
||||
const label = readStringParam(params, "label");
|
||||
const agentId = readStringParam(params, "agentId");
|
||||
const search = readStringParam(params, "search");
|
||||
const includeDerivedTitles = params.includeDerivedTitles === true ? true : undefined;
|
||||
const includeLastMessage = params.includeLastMessage === true ? true : undefined;
|
||||
const includeDerivedTitles = params.includeDerivedTitles === true;
|
||||
const includeLastMessage = params.includeLastMessage === true;
|
||||
const gatewayCall = opts?.callGateway ?? callGateway;
|
||||
|
||||
const list = await gatewayCall<{ sessions: Array<SessionListRow>; path: string }>({
|
||||
@@ -117,8 +119,6 @@ export function createSessionsListTool(opts?: {
|
||||
label,
|
||||
agentId,
|
||||
search,
|
||||
includeDerivedTitles,
|
||||
includeLastMessage,
|
||||
includeGlobal: !restrictToSpawned,
|
||||
includeUnknown: !restrictToSpawned,
|
||||
spawnedBy: restrictToSpawned ? effectiveRequesterKey : undefined,
|
||||
@@ -309,6 +309,32 @@ export function createSessionsListTool(opts?: {
|
||||
lastAccountId,
|
||||
transcriptPath,
|
||||
};
|
||||
if (sessionId && (includeDerivedTitles || includeLastMessage)) {
|
||||
const fields = readSessionTitleFieldsFromTranscript(
|
||||
sessionId,
|
||||
storePath,
|
||||
sessionFile,
|
||||
resolvedAgentId,
|
||||
);
|
||||
if (includeDerivedTitles && !row.derivedTitle) {
|
||||
const derivedTitle = deriveSessionTitle(
|
||||
{
|
||||
sessionId,
|
||||
displayName: row.displayName,
|
||||
label: row.label,
|
||||
subject: readStringValue((entry as { subject?: unknown }).subject),
|
||||
updatedAt: typeof row.updatedAt === "number" ? row.updatedAt : 0,
|
||||
},
|
||||
fields.firstUserMessage,
|
||||
);
|
||||
if (derivedTitle) {
|
||||
row.derivedTitle = derivedTitle;
|
||||
}
|
||||
}
|
||||
if (includeLastMessage && !row.lastMessagePreview && fields.lastMessagePreview) {
|
||||
row.lastMessagePreview = fields.lastMessagePreview;
|
||||
}
|
||||
}
|
||||
if (messageLimit > 0) {
|
||||
const resolvedKey = resolveInternalSessionKey({
|
||||
key,
|
||||
|
||||
Reference in New Issue
Block a user