feat(FN-4075): repair room reply session creation

Fixes FN-4075: repairs room reply session creation logic in the chat module, with accompanying tests added to cover the fix.

Fusion-Task-Id: FN-4075
This commit is contained in:
Fusion
2026-05-11 22:38:41 -07:00
committed by gsxdsm
parent 588f2acb0e
commit c6edf5f49f
2 changed files with 73 additions and 11 deletions

View File

@@ -263,6 +263,54 @@ describe("Chat orchestration — rooms (FN-3805..FN-3811 contract)", () => {
);
});
it("passes resolved-session runtime options when generating room replies", async () => {
mockChatStore.listRoomMembers.mockReturnValue([
{ roomId: "room-1", agentId: "agent-a", role: "member", addedAt: "2026-01-01" },
]);
mockAgentStore.listAgents.mockResolvedValue([
{
id: "agent-a",
name: "Alpha",
role: "executor",
runtimeConfig: { model: "anthropic/claude-sonnet-4-5", runtimeHint: "openclaw" },
},
]);
mockAgentStore.getAgent.mockResolvedValue({
id: "agent-a",
name: "Alpha",
role: "executor",
runtimeConfig: { model: "anthropic/claude-sonnet-4-5", runtimeHint: "openclaw" },
});
const createResolvedSession = vi.fn().mockResolvedValue({
session: {
prompt: vi.fn().mockResolvedValue(undefined),
dispose: vi.fn(),
state: {
messages: [{ role: "assistant", content: "Room reply" }],
},
},
});
__setCreateResolvedAgentSession(createResolvedSession as any);
const manager = new ChatManager(mockChatStore as any, "/tmp", mockAgentStore as any);
await manager.sendRoomMessage("room-1", "hello @Alpha");
expect(createResolvedSession).toHaveBeenCalledWith(expect.objectContaining({
sessionPurpose: "heartbeat",
pluginRunner: undefined,
runtimeHint: "openclaw",
cwd: "/tmp",
systemPrompt: expect.any(String),
tools: "coding",
defaultProvider: "anthropic",
defaultModelId: "claude-sonnet-4-5",
}));
expect(createResolvedSession.mock.calls[0]?.[0]).not.toHaveProperty("createFnAgentArgs");
expect(createResolvedSession.mock.calls[0]?.[0]).not.toHaveProperty("resolvedProvider");
expect(createResolvedSession.mock.calls[0]?.[0]).not.toHaveProperty("resolvedModel");
});
it("throws surfaced error when all room responders fail to reply", async () => {
mockChatStore.listRoomMembers.mockReturnValue([
{ roomId: "room-1", agentId: "agent-a", role: "member", addedAt: "2026-01-01" },

View File

@@ -1015,18 +1015,32 @@ export class ChatManager {
input.content,
].join("\n\n");
const responderRuntimeModel = extractRuntimeModel(input.responder.runtimeConfig);
const effectiveModelProvider = input.modelProvider ?? responderRuntimeModel.provider;
const effectiveModelId = input.modelId ?? responderRuntimeModel.modelId;
const chatModelSettings = await this.getChatModelSettings();
const allowFallback = !(input.modelProvider && input.modelId)
&& !(responderRuntimeModel.provider && responderRuntimeModel.modelId);
const resolvedSession = await createResolvedAgentSession({
createFnAgent,
resolvedProvider: input.modelProvider,
resolvedModel: input.modelId,
defaultModelProvider: input.modelProvider,
defaultModelId: input.modelId,
createFnAgentArgs: {
rootDir: this.rootDir,
modelProvider: input.modelProvider,
modelId: input.modelId,
systemPrompt,
},
sessionPurpose: "heartbeat",
pluginRunner: this.pluginRunner,
runtimeHint: extractRuntimeHint(input.responder.runtimeConfig),
cwd: this.rootDir,
systemPrompt,
tools: "coding",
...(effectiveModelProvider && effectiveModelId
? {
defaultProvider: effectiveModelProvider,
defaultModelId: effectiveModelId,
}
: {}),
...(allowFallback && chatModelSettings.fallbackProvider && chatModelSettings.fallbackModelId
? {
fallbackProvider: chatModelSettings.fallbackProvider,
fallbackModelId: chatModelSettings.fallbackModelId,
}
: {}),
});
try {