mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 10:37:41 +00:00
refactor(test): dedupe agent and status command fixtures
This commit is contained in:
@@ -57,6 +57,24 @@ async function withTempStore(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mockGatewaySuccessReply(text = "hello") {
|
||||||
|
vi.mocked(callGateway).mockResolvedValue({
|
||||||
|
runId: "idem-1",
|
||||||
|
status: "ok",
|
||||||
|
result: {
|
||||||
|
payloads: [{ text }],
|
||||||
|
meta: { stub: true },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function mockLocalAgentReply(text = "local") {
|
||||||
|
vi.mocked(agentCommand).mockImplementationOnce(async (_opts, rt) => {
|
||||||
|
rt.log?.(text);
|
||||||
|
return { payloads: [{ text }], meta: { stub: true } };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
@@ -64,14 +82,7 @@ beforeEach(() => {
|
|||||||
describe("agentCliCommand", () => {
|
describe("agentCliCommand", () => {
|
||||||
it("uses a timer-safe max gateway timeout when --timeout is 0", async () => {
|
it("uses a timer-safe max gateway timeout when --timeout is 0", async () => {
|
||||||
await withTempStore(async () => {
|
await withTempStore(async () => {
|
||||||
vi.mocked(callGateway).mockResolvedValue({
|
mockGatewaySuccessReply();
|
||||||
runId: "idem-1",
|
|
||||||
status: "ok",
|
|
||||||
result: {
|
|
||||||
payloads: [{ text: "hello" }],
|
|
||||||
meta: { stub: true },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await agentCliCommand({ message: "hi", to: "+1555", timeout: "0" }, runtime);
|
await agentCliCommand({ message: "hi", to: "+1555", timeout: "0" }, runtime);
|
||||||
|
|
||||||
@@ -83,14 +94,7 @@ describe("agentCliCommand", () => {
|
|||||||
|
|
||||||
it("uses gateway by default", async () => {
|
it("uses gateway by default", async () => {
|
||||||
await withTempStore(async () => {
|
await withTempStore(async () => {
|
||||||
vi.mocked(callGateway).mockResolvedValue({
|
mockGatewaySuccessReply();
|
||||||
runId: "idem-1",
|
|
||||||
status: "ok",
|
|
||||||
result: {
|
|
||||||
payloads: [{ text: "hello" }],
|
|
||||||
meta: { stub: true },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await agentCliCommand({ message: "hi", to: "+1555" }, runtime);
|
await agentCliCommand({ message: "hi", to: "+1555" }, runtime);
|
||||||
|
|
||||||
@@ -103,10 +107,7 @@ describe("agentCliCommand", () => {
|
|||||||
it("falls back to embedded agent when gateway fails", async () => {
|
it("falls back to embedded agent when gateway fails", async () => {
|
||||||
await withTempStore(async () => {
|
await withTempStore(async () => {
|
||||||
vi.mocked(callGateway).mockRejectedValue(new Error("gateway not connected"));
|
vi.mocked(callGateway).mockRejectedValue(new Error("gateway not connected"));
|
||||||
vi.mocked(agentCommand).mockImplementationOnce(async (_opts, rt) => {
|
mockLocalAgentReply();
|
||||||
rt.log?.("local");
|
|
||||||
return { payloads: [{ text: "local" }], meta: { stub: true } };
|
|
||||||
});
|
|
||||||
|
|
||||||
await agentCliCommand({ message: "hi", to: "+1555" }, runtime);
|
await agentCliCommand({ message: "hi", to: "+1555" }, runtime);
|
||||||
|
|
||||||
@@ -118,10 +119,7 @@ describe("agentCliCommand", () => {
|
|||||||
|
|
||||||
it("skips gateway when --local is set", async () => {
|
it("skips gateway when --local is set", async () => {
|
||||||
await withTempStore(async () => {
|
await withTempStore(async () => {
|
||||||
vi.mocked(agentCommand).mockImplementationOnce(async (_opts, rt) => {
|
mockLocalAgentReply();
|
||||||
rt.log?.("local");
|
|
||||||
return { payloads: [{ text: "local" }], meta: { stub: true } };
|
|
||||||
});
|
|
||||||
|
|
||||||
await agentCliCommand(
|
await agentCliCommand(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ function mockConfig(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function writeSessionStoreSeed(
|
||||||
|
storePath: string,
|
||||||
|
sessions: Record<string, Record<string, unknown>>,
|
||||||
|
) {
|
||||||
|
fs.mkdirSync(path.dirname(storePath), { recursive: true });
|
||||||
|
fs.writeFileSync(storePath, JSON.stringify(sessions, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
vi.mocked(runEmbeddedPiAgent).mockResolvedValue({
|
vi.mocked(runEmbeddedPiAgent).mockResolvedValue({
|
||||||
@@ -114,21 +122,13 @@ describe("agentCommand", () => {
|
|||||||
it("resumes when session-id is provided", async () => {
|
it("resumes when session-id is provided", async () => {
|
||||||
await withTempHome(async (home) => {
|
await withTempHome(async (home) => {
|
||||||
const store = path.join(home, "sessions.json");
|
const store = path.join(home, "sessions.json");
|
||||||
fs.mkdirSync(path.dirname(store), { recursive: true });
|
writeSessionStoreSeed(store, {
|
||||||
fs.writeFileSync(
|
foo: {
|
||||||
store,
|
sessionId: "session-123",
|
||||||
JSON.stringify(
|
updatedAt: Date.now(),
|
||||||
{
|
systemSent: true,
|
||||||
foo: {
|
},
|
||||||
sessionId: "session-123",
|
});
|
||||||
updatedAt: Date.now(),
|
|
||||||
systemSent: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
2,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
mockConfig(home, store);
|
mockConfig(home, store);
|
||||||
|
|
||||||
await agentCommand({ message: "resume me", sessionId: "session-123" }, runtime);
|
await agentCommand({ message: "resume me", sessionId: "session-123" }, runtime);
|
||||||
@@ -199,22 +199,14 @@ describe("agentCommand", () => {
|
|||||||
it("uses default fallback list for session model overrides", async () => {
|
it("uses default fallback list for session model overrides", async () => {
|
||||||
await withTempHome(async (home) => {
|
await withTempHome(async (home) => {
|
||||||
const store = path.join(home, "sessions.json");
|
const store = path.join(home, "sessions.json");
|
||||||
fs.mkdirSync(path.dirname(store), { recursive: true });
|
writeSessionStoreSeed(store, {
|
||||||
fs.writeFileSync(
|
"agent:main:subagent:test": {
|
||||||
store,
|
sessionId: "session-subagent",
|
||||||
JSON.stringify(
|
updatedAt: Date.now(),
|
||||||
{
|
providerOverride: "anthropic",
|
||||||
"agent:main:subagent:test": {
|
modelOverride: "claude-opus-4-5",
|
||||||
sessionId: "session-subagent",
|
},
|
||||||
updatedAt: Date.now(),
|
});
|
||||||
providerOverride: "anthropic",
|
|
||||||
modelOverride: "claude-opus-4-5",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
2,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
mockConfig(home, store, {
|
mockConfig(home, store, {
|
||||||
model: {
|
model: {
|
||||||
@@ -264,20 +256,12 @@ describe("agentCommand", () => {
|
|||||||
it("keeps explicit sessionKey even when sessionId exists elsewhere", async () => {
|
it("keeps explicit sessionKey even when sessionId exists elsewhere", async () => {
|
||||||
await withTempHome(async (home) => {
|
await withTempHome(async (home) => {
|
||||||
const store = path.join(home, "sessions.json");
|
const store = path.join(home, "sessions.json");
|
||||||
fs.mkdirSync(path.dirname(store), { recursive: true });
|
writeSessionStoreSeed(store, {
|
||||||
fs.writeFileSync(
|
"agent:main:main": {
|
||||||
store,
|
sessionId: "sess-main",
|
||||||
JSON.stringify(
|
updatedAt: Date.now(),
|
||||||
{
|
},
|
||||||
"agent:main:main": {
|
});
|
||||||
sessionId: "sess-main",
|
|
||||||
updatedAt: Date.now(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
2,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
mockConfig(home, store);
|
mockConfig(home, store);
|
||||||
|
|
||||||
await agentCommand(
|
await agentCommand(
|
||||||
|
|||||||
@@ -43,6 +43,14 @@ function getWrittenMainIdentity() {
|
|||||||
return written.agents?.list?.find((entry) => entry.id === "main")?.identity;
|
return written.agents?.list?.find((entry) => entry.id === "main")?.identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function runIdentityCommandFromWorkspace(workspace: string, fromIdentity = true) {
|
||||||
|
configMocks.readConfigFileSnapshot.mockResolvedValue({
|
||||||
|
...baseConfigSnapshot,
|
||||||
|
config: { agents: { list: [{ id: "main", workspace }] } },
|
||||||
|
});
|
||||||
|
await agentsSetIdentityCommand({ workspace, fromIdentity }, runtime);
|
||||||
|
}
|
||||||
|
|
||||||
describe("agents set-identity command", () => {
|
describe("agents set-identity command", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
configMocks.readConfigFileSnapshot.mockReset();
|
configMocks.readConfigFileSnapshot.mockReset();
|
||||||
@@ -171,12 +179,7 @@ describe("agents set-identity command", () => {
|
|||||||
const { workspace } = await createIdentityWorkspace();
|
const { workspace } = await createIdentityWorkspace();
|
||||||
await writeIdentityFile(workspace, ["- Avatar: avatars/only.png"]);
|
await writeIdentityFile(workspace, ["- Avatar: avatars/only.png"]);
|
||||||
|
|
||||||
configMocks.readConfigFileSnapshot.mockResolvedValue({
|
await runIdentityCommandFromWorkspace(workspace);
|
||||||
...baseConfigSnapshot,
|
|
||||||
config: { agents: { list: [{ id: "main", workspace }] } },
|
|
||||||
});
|
|
||||||
|
|
||||||
await agentsSetIdentityCommand({ workspace, fromIdentity: true }, runtime);
|
|
||||||
|
|
||||||
expect(getWrittenMainIdentity()).toEqual({
|
expect(getWrittenMainIdentity()).toEqual({
|
||||||
avatar: "avatars/only.png",
|
avatar: "avatars/only.png",
|
||||||
@@ -202,12 +205,7 @@ describe("agents set-identity command", () => {
|
|||||||
it("errors when identity data is missing", async () => {
|
it("errors when identity data is missing", async () => {
|
||||||
const { workspace } = await createIdentityWorkspace();
|
const { workspace } = await createIdentityWorkspace();
|
||||||
|
|
||||||
configMocks.readConfigFileSnapshot.mockResolvedValue({
|
await runIdentityCommandFromWorkspace(workspace);
|
||||||
...baseConfigSnapshot,
|
|
||||||
config: { agents: { list: [{ id: "main", workspace }] } },
|
|
||||||
});
|
|
||||||
|
|
||||||
await agentsSetIdentityCommand({ workspace, fromIdentity: true }, runtime);
|
|
||||||
|
|
||||||
expect(runtime.error).toHaveBeenCalledWith(expect.stringContaining("No identity data found"));
|
expect(runtime.error).toHaveBeenCalledWith(expect.stringContaining("No identity data found"));
|
||||||
expect(runtime.exit).toHaveBeenCalledWith(1);
|
expect(runtime.exit).toHaveBeenCalledWith(1);
|
||||||
|
|||||||
@@ -12,20 +12,79 @@ afterAll(() => {
|
|||||||
envSnapshot.restore();
|
envSnapshot.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
const mocks = vi.hoisted(() => ({
|
function createDefaultSessionStoreEntry() {
|
||||||
loadSessionStore: vi.fn().mockReturnValue({
|
return {
|
||||||
|
updatedAt: Date.now() - 60_000,
|
||||||
|
verboseLevel: "on",
|
||||||
|
thinkingLevel: "low",
|
||||||
|
inputTokens: 2_000,
|
||||||
|
outputTokens: 3_000,
|
||||||
|
totalTokens: 5_000,
|
||||||
|
contextTokens: 10_000,
|
||||||
|
model: "pi:opus",
|
||||||
|
sessionId: "abc123",
|
||||||
|
systemSent: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createUnknownUsageSessionStore() {
|
||||||
|
return {
|
||||||
"+1000": {
|
"+1000": {
|
||||||
updatedAt: Date.now() - 60_000,
|
updatedAt: Date.now() - 60_000,
|
||||||
verboseLevel: "on",
|
|
||||||
thinkingLevel: "low",
|
|
||||||
inputTokens: 2_000,
|
inputTokens: 2_000,
|
||||||
outputTokens: 3_000,
|
outputTokens: 3_000,
|
||||||
totalTokens: 5_000,
|
|
||||||
contextTokens: 10_000,
|
contextTokens: 10_000,
|
||||||
model: "pi:opus",
|
model: "pi:opus",
|
||||||
sessionId: "abc123",
|
|
||||||
systemSent: true,
|
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createChannelIssueCollector(channel: string) {
|
||||||
|
return (accounts: Array<Record<string, unknown>>) =>
|
||||||
|
accounts
|
||||||
|
.filter((account) => typeof account.lastError === "string" && account.lastError)
|
||||||
|
.map((account) => ({
|
||||||
|
channel,
|
||||||
|
accountId: typeof account.accountId === "string" ? account.accountId : "default",
|
||||||
|
message: `Channel error: ${String(account.lastError)}`,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function createErrorChannelPlugin(params: { id: string; label: string; docsPath: string }) {
|
||||||
|
return {
|
||||||
|
id: params.id,
|
||||||
|
meta: {
|
||||||
|
id: params.id,
|
||||||
|
label: params.label,
|
||||||
|
selectionLabel: params.label,
|
||||||
|
docsPath: params.docsPath,
|
||||||
|
blurb: "mock",
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
listAccountIds: () => ["default"],
|
||||||
|
resolveAccount: () => ({}),
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
collectStatusIssues: createChannelIssueCollector(params.id),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function withUnknownUsageStore(run: () => Promise<void>) {
|
||||||
|
const originalLoadSessionStore = mocks.loadSessionStore.getMockImplementation();
|
||||||
|
mocks.loadSessionStore.mockReturnValue(createUnknownUsageSessionStore());
|
||||||
|
try {
|
||||||
|
await run();
|
||||||
|
} finally {
|
||||||
|
if (originalLoadSessionStore) {
|
||||||
|
mocks.loadSessionStore.mockImplementation(originalLoadSessionStore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mocks = vi.hoisted(() => ({
|
||||||
|
loadSessionStore: vi.fn().mockReturnValue({
|
||||||
|
"+1000": createDefaultSessionStoreEntry(),
|
||||||
}),
|
}),
|
||||||
resolveMainSessionKey: vi.fn().mockReturnValue("agent:main:main"),
|
resolveMainSessionKey: vi.fn().mockReturnValue("agent:main:main"),
|
||||||
resolveStorePath: vi.fn().mockReturnValue("/tmp/sessions.json"),
|
resolveStorePath: vi.fn().mockReturnValue("/tmp/sessions.json"),
|
||||||
@@ -148,52 +207,18 @@ vi.mock("../channels/plugins/index.js", () => ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "signal",
|
...createErrorChannelPlugin({
|
||||||
meta: {
|
|
||||||
id: "signal",
|
id: "signal",
|
||||||
label: "Signal",
|
label: "Signal",
|
||||||
selectionLabel: "Signal",
|
|
||||||
docsPath: "/platforms/signal",
|
docsPath: "/platforms/signal",
|
||||||
blurb: "mock",
|
}),
|
||||||
},
|
|
||||||
config: {
|
|
||||||
listAccountIds: () => ["default"],
|
|
||||||
resolveAccount: () => ({}),
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
collectStatusIssues: (accounts: Array<Record<string, unknown>>) =>
|
|
||||||
accounts
|
|
||||||
.filter((account) => typeof account.lastError === "string" && account.lastError)
|
|
||||||
.map((account) => ({
|
|
||||||
channel: "signal",
|
|
||||||
accountId: typeof account.accountId === "string" ? account.accountId : "default",
|
|
||||||
message: `Channel error: ${String(account.lastError)}`,
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "imessage",
|
...createErrorChannelPlugin({
|
||||||
meta: {
|
|
||||||
id: "imessage",
|
id: "imessage",
|
||||||
label: "iMessage",
|
label: "iMessage",
|
||||||
selectionLabel: "iMessage",
|
|
||||||
docsPath: "/platforms/mac",
|
docsPath: "/platforms/mac",
|
||||||
blurb: "mock",
|
}),
|
||||||
},
|
|
||||||
config: {
|
|
||||||
listAccountIds: () => ["default"],
|
|
||||||
resolveAccount: () => ({}),
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
collectStatusIssues: (accounts: Array<Record<string, unknown>>) =>
|
|
||||||
accounts
|
|
||||||
.filter((account) => typeof account.lastError === "string" && account.lastError)
|
|
||||||
.map((account) => ({
|
|
||||||
channel: "imessage",
|
|
||||||
accountId: typeof account.accountId === "string" ? account.accountId : "default",
|
|
||||||
message: `Channel error: ${String(account.lastError)}`,
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
] as unknown,
|
] as unknown,
|
||||||
}));
|
}));
|
||||||
@@ -210,9 +235,13 @@ vi.mock("../gateway/call.js", async (importOriginal) => {
|
|||||||
const actual = await importOriginal<typeof import("../gateway/call.js")>();
|
const actual = await importOriginal<typeof import("../gateway/call.js")>();
|
||||||
return { ...actual, callGateway: mocks.callGateway };
|
return { ...actual, callGateway: mocks.callGateway };
|
||||||
});
|
});
|
||||||
vi.mock("../gateway/session-utils.js", () => ({
|
vi.mock("../gateway/session-utils.js", async (importOriginal) => {
|
||||||
listAgentsForGateway: mocks.listAgentsForGateway,
|
const actual = await importOriginal<typeof import("../gateway/session-utils.js")>();
|
||||||
}));
|
return {
|
||||||
|
...actual,
|
||||||
|
listAgentsForGateway: mocks.listAgentsForGateway,
|
||||||
|
};
|
||||||
|
});
|
||||||
vi.mock("../infra/openclaw-root.js", () => ({
|
vi.mock("../infra/openclaw-root.js", () => ({
|
||||||
resolveOpenClawPackageRoot: vi.fn().mockResolvedValue("/tmp/openclaw"),
|
resolveOpenClawPackageRoot: vi.fn().mockResolvedValue("/tmp/openclaw"),
|
||||||
}));
|
}));
|
||||||
@@ -318,52 +347,24 @@ describe("statusCommand", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("surfaces unknown usage when totalTokens is missing", async () => {
|
it("surfaces unknown usage when totalTokens is missing", async () => {
|
||||||
const originalLoadSessionStore = mocks.loadSessionStore.getMockImplementation();
|
await withUnknownUsageStore(async () => {
|
||||||
mocks.loadSessionStore.mockReturnValue({
|
(runtime.log as vi.Mock).mockClear();
|
||||||
"+1000": {
|
await statusCommand({ json: true }, runtime as never);
|
||||||
updatedAt: Date.now() - 60_000,
|
const payload = JSON.parse((runtime.log as vi.Mock).mock.calls.at(-1)?.[0]);
|
||||||
inputTokens: 2_000,
|
expect(payload.sessions.recent[0].totalTokens).toBeNull();
|
||||||
outputTokens: 3_000,
|
expect(payload.sessions.recent[0].totalTokensFresh).toBe(false);
|
||||||
contextTokens: 10_000,
|
expect(payload.sessions.recent[0].percentUsed).toBeNull();
|
||||||
model: "pi:opus",
|
expect(payload.sessions.recent[0].remainingTokens).toBeNull();
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
(runtime.log as vi.Mock).mockClear();
|
|
||||||
await statusCommand({ json: true }, runtime as never);
|
|
||||||
const payload = JSON.parse((runtime.log as vi.Mock).mock.calls.at(-1)?.[0]);
|
|
||||||
expect(payload.sessions.recent[0].totalTokens).toBeNull();
|
|
||||||
expect(payload.sessions.recent[0].totalTokensFresh).toBe(false);
|
|
||||||
expect(payload.sessions.recent[0].percentUsed).toBeNull();
|
|
||||||
expect(payload.sessions.recent[0].remainingTokens).toBeNull();
|
|
||||||
|
|
||||||
if (originalLoadSessionStore) {
|
|
||||||
mocks.loadSessionStore.mockImplementation(originalLoadSessionStore);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("prints unknown usage in formatted output when totalTokens is missing", async () => {
|
it("prints unknown usage in formatted output when totalTokens is missing", async () => {
|
||||||
const originalLoadSessionStore = mocks.loadSessionStore.getMockImplementation();
|
await withUnknownUsageStore(async () => {
|
||||||
mocks.loadSessionStore.mockReturnValue({
|
|
||||||
"+1000": {
|
|
||||||
updatedAt: Date.now() - 60_000,
|
|
||||||
inputTokens: 2_000,
|
|
||||||
outputTokens: 3_000,
|
|
||||||
contextTokens: 10_000,
|
|
||||||
model: "pi:opus",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
(runtime.log as vi.Mock).mockClear();
|
(runtime.log as vi.Mock).mockClear();
|
||||||
await statusCommand({}, runtime as never);
|
await statusCommand({}, runtime as never);
|
||||||
const logs = (runtime.log as vi.Mock).mock.calls.map((c) => String(c[0]));
|
const logs = (runtime.log as vi.Mock).mock.calls.map((c) => String(c[0]));
|
||||||
expect(logs.some((line) => line.includes("unknown/") && line.includes("(?%)"))).toBe(true);
|
expect(logs.some((line) => line.includes("unknown/") && line.includes("(?%)"))).toBe(true);
|
||||||
} finally {
|
});
|
||||||
if (originalLoadSessionStore) {
|
|
||||||
mocks.loadSessionStore.mockImplementation(originalLoadSessionStore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("prints formatted lines otherwise", async () => {
|
it("prints formatted lines otherwise", async () => {
|
||||||
@@ -501,18 +502,7 @@ describe("statusCommand", () => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
"+1000": {
|
"+1000": createDefaultSessionStoreEntry(),
|
||||||
updatedAt: Date.now() - 60_000,
|
|
||||||
verboseLevel: "on",
|
|
||||||
thinkingLevel: "low",
|
|
||||||
inputTokens: 2_000,
|
|
||||||
outputTokens: 3_000,
|
|
||||||
totalTokens: 5_000,
|
|
||||||
contextTokens: 10_000,
|
|
||||||
model: "pi:opus",
|
|
||||||
sessionId: "abc123",
|
|
||||||
systemSent: true,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,23 @@ import { describe, expect, it } from "vitest";
|
|||||||
import type { StatusSummary } from "./status.types.js";
|
import type { StatusSummary } from "./status.types.js";
|
||||||
import { redactSensitiveStatusSummary } from "./status.summary.js";
|
import { redactSensitiveStatusSummary } from "./status.summary.js";
|
||||||
|
|
||||||
|
function createRecentSessionRow() {
|
||||||
|
return {
|
||||||
|
key: "main",
|
||||||
|
kind: "direct" as const,
|
||||||
|
sessionId: "sess-1",
|
||||||
|
updatedAt: 1,
|
||||||
|
age: 2,
|
||||||
|
totalTokens: 3,
|
||||||
|
totalTokensFresh: true,
|
||||||
|
remainingTokens: 4,
|
||||||
|
percentUsed: 5,
|
||||||
|
model: "gpt-5",
|
||||||
|
contextTokens: 200_000,
|
||||||
|
flags: ["id:sess-1"],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
describe("redactSensitiveStatusSummary", () => {
|
describe("redactSensitiveStatusSummary", () => {
|
||||||
it("removes sensitive session and path details while preserving summary structure", () => {
|
it("removes sensitive session and path details while preserving summary structure", () => {
|
||||||
const input: StatusSummary = {
|
const input: StatusSummary = {
|
||||||
@@ -15,43 +32,13 @@ describe("redactSensitiveStatusSummary", () => {
|
|||||||
paths: ["/tmp/openclaw/sessions.json"],
|
paths: ["/tmp/openclaw/sessions.json"],
|
||||||
count: 1,
|
count: 1,
|
||||||
defaults: { model: "gpt-5", contextTokens: 200_000 },
|
defaults: { model: "gpt-5", contextTokens: 200_000 },
|
||||||
recent: [
|
recent: [createRecentSessionRow()],
|
||||||
{
|
|
||||||
key: "main",
|
|
||||||
kind: "direct",
|
|
||||||
sessionId: "sess-1",
|
|
||||||
updatedAt: 1,
|
|
||||||
age: 2,
|
|
||||||
totalTokens: 3,
|
|
||||||
totalTokensFresh: true,
|
|
||||||
remainingTokens: 4,
|
|
||||||
percentUsed: 5,
|
|
||||||
model: "gpt-5",
|
|
||||||
contextTokens: 200_000,
|
|
||||||
flags: ["id:sess-1"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
byAgent: [
|
byAgent: [
|
||||||
{
|
{
|
||||||
agentId: "main",
|
agentId: "main",
|
||||||
path: "/tmp/openclaw/main-sessions.json",
|
path: "/tmp/openclaw/main-sessions.json",
|
||||||
count: 1,
|
count: 1,
|
||||||
recent: [
|
recent: [createRecentSessionRow()],
|
||||||
{
|
|
||||||
key: "main",
|
|
||||||
kind: "direct",
|
|
||||||
sessionId: "sess-1",
|
|
||||||
updatedAt: 1,
|
|
||||||
age: 2,
|
|
||||||
totalTokens: 3,
|
|
||||||
totalTokensFresh: true,
|
|
||||||
remainingTokens: 4,
|
|
||||||
percentUsed: 5,
|
|
||||||
model: "gpt-5",
|
|
||||||
contextTokens: 200_000,
|
|
||||||
flags: ["id:sess-1"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user