




















@@ -12,13 +12,25 @@ vi.mock("../../infra/session-cost-usage.js", async () => {
1212startDate: "2026-02-01",
1313endDate: "2026-02-02",
1414daily: [],
15-totals: { totalTokens: 1, input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalCost: 0 },
15+totals: {
16+input: 0,
17+output: 0,
18+cacheRead: 0,
19+cacheWrite: 0,
20+totalTokens: 1,
21+totalCost: 0,
22+inputCost: 0,
23+outputCost: 0,
24+cacheReadCost: 0,
25+cacheWriteCost: 0,
26+missingCostEntries: 0,
27+},
1628})),
1729};
1830});
19312032import { loadCostUsageSummaryFromCache } from "../../infra/session-cost-usage.js";
21-import { testApi } from "./usage.js";
33+import { testApi, usageHandlers } from "./usage.js";
22342335describe("gateway usage helpers", () => {
2436const dayMs = 24 * 60 * 60 * 1000;
@@ -161,4 +173,78 @@ describe("gateway usage helpers", () => {
161173"background",
162174);
163175});
176+177+it("keeps cost usage cache entries scoped by agentId", async () => {
178+const config = {} as OpenClawConfig;
179+180+await testApi.loadCostUsageSummaryCached({
181+startMs: 1,
182+endMs: 2,
183+ config,
184+agentId: "main",
185+});
186+await testApi.loadCostUsageSummaryCached({
187+startMs: 1,
188+endMs: 2,
189+ config,
190+agentId: "research",
191+});
192+await testApi.loadCostUsageSummaryCached({
193+startMs: 1,
194+endMs: 2,
195+ config,
196+agentId: "research",
197+});
198+199+expect(vi.mocked(loadCostUsageSummaryFromCache)).toHaveBeenCalledTimes(2);
200+expect(vi.mocked(loadCostUsageSummaryFromCache).mock.calls.at(0)?.[0]).toMatchObject({
201+agentId: "main",
202+});
203+expect(vi.mocked(loadCostUsageSummaryFromCache).mock.calls.at(1)?.[0]).toMatchObject({
204+agentId: "research",
205+});
206+});
207+208+it("passes usage.cost agentId through to the cost summary loader", async () => {
209+const respond = vi.fn();
210+211+await usageHandlers["usage.cost"]({
212+ respond,
213+params: { startDate: "2026-02-01", endDate: "2026-02-02", agentId: "research" },
214+context: { getRuntimeConfig: () => ({}) },
215+} as unknown as Parameters<(typeof usageHandlers)["usage.cost"]>[0]);
216+217+expect(respond).toHaveBeenCalledWith(true, expect.any(Object), undefined);
218+expect(vi.mocked(loadCostUsageSummaryFromCache)).toHaveBeenCalledWith(
219+expect.objectContaining({ agentId: "research" }),
220+);
221+});
222+223+it("passes usage.cost all-agent scope through to all configured agent loaders", async () => {
224+const respond = vi.fn();
225+226+await usageHandlers["usage.cost"]({
227+ respond,
228+params: { startDate: "2026-02-01", endDate: "2026-02-02", agentScope: "all" },
229+context: {
230+getRuntimeConfig: () => ({
231+agents: { list: [{ id: "main" }, { id: "research" }] },
232+}),
233+},
234+} as unknown as Parameters<(typeof usageHandlers)["usage.cost"]>[0]);
235+236+expect(respond).toHaveBeenCalledWith(
237+true,
238+expect.objectContaining({
239+totals: expect.objectContaining({ totalTokens: 2 }),
240+}),
241+undefined,
242+);
243+expect(vi.mocked(loadCostUsageSummaryFromCache)).toHaveBeenCalledWith(
244+expect.objectContaining({ agentId: "main" }),
245+);
246+expect(vi.mocked(loadCostUsageSummaryFromCache)).toHaveBeenCalledWith(
247+expect.objectContaining({ agentId: "research" }),
248+);
249+});
164250});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。