fix: stop followup queue drain cfg crash

This commit is contained in:
Tyler Yust 2026-03-12 16:49:43 -07:00
parent cfef9d5d45
commit fe074ec8e4
2 changed files with 60 additions and 1 deletions

View File

@ -4,6 +4,7 @@ import path from "node:path";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { loadSessionStore, saveSessionStore, type SessionEntry } from "../../config/sessions.js";
import type { FollowupRun } from "./queue.js";
import * as sessionRunAccounting from "./session-run-accounting.js";
import { createMockTypingController } from "./test-helpers.js";
const runEmbeddedPiAgentMock = vi.fn();
@ -415,6 +416,64 @@ describe("createFollowupRunner messaging tool dedupe", () => {
expect(store[sessionKey]?.outputTokens).toBe(50);
});
it("passes queued config into usage persistence during drained followups", async () => {
const storePath = path.join(
await fs.mkdtemp(path.join(tmpdir(), "openclaw-followup-usage-cfg-")),
"sessions.json",
);
const sessionKey = "main";
const sessionEntry: SessionEntry = { sessionId: "session", updatedAt: Date.now() };
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: sessionEntry };
await saveSessionStore(storePath, sessionStore);
const cfg = {
messages: {
responsePrefix: "agent",
},
};
const persistSpy = vi.spyOn(sessionRunAccounting, "persistRunSessionUsage");
runEmbeddedPiAgentMock.mockResolvedValueOnce({
payloads: [{ text: "hello world!" }],
meta: {
agentMeta: {
usage: { input: 10, output: 5 },
lastCallUsage: { input: 6, output: 3 },
model: "claude-opus-4-5",
},
},
});
const runner = createFollowupRunner({
opts: { onBlockReply: createAsyncReplySpy() },
typing: createMockTypingController(),
typingMode: "instant",
defaultModel: "anthropic/claude-opus-4-5",
sessionEntry,
sessionStore,
sessionKey,
storePath,
});
await expect(
runner(
createQueuedRun({
run: {
config: cfg,
},
}),
),
).resolves.toBeUndefined();
expect(persistSpy).toHaveBeenCalledWith(
expect.objectContaining({
storePath,
sessionKey,
cfg,
}),
);
persistSpy.mockRestore();
});
it("does not fall back to dispatcher when cross-channel origin routing fails", async () => {
routeReplyMock.mockResolvedValueOnce({
ok: false,

View File

@ -254,7 +254,7 @@ export function createFollowupRunner(params: {
await persistRunSessionUsage({
storePath,
sessionKey,
cfg,
cfg: queued.run.config,
usage,
lastCallUsage: runResult.meta?.agentMeta?.lastCallUsage,
promptTokens,