FN-7909: add room-level thinking effort override for Chat Rooms

Adds a per-room thinking-effort (reasoning level) override for Chat Rooms so all room responders can share a consistent override instead of relying only on per-agent/global defaults.

- Persist `chat_rooms.thinkingLevel` with a new core DB migration and store read/write support
- Extend chat-store and chat-types with thinkingLevel plumbing for room create/update
- Wire the dashboard chat room API/routes and legacy handlers to accept and return thinkingLevel
- Add a ChatView room settings control (with CSS) and useChatRooms hook support for setting/clearing the override
- Resolve room responder defaultThinkingLevel from the room override when present
- Update docs (dashboard-guide, settings-reference) and add a minor changeset for the feature

Files changed:
 .changeset/fn-7909-room-thinking-level.md          |  7 +++
 docs/dashboard-guide.md                            |  1 +
 docs/settings-reference.md                         |  2 +-
 packages/core/src/__tests__/chat-store.test.ts     | 21 ++++++++
 packages/core/src/__tests__/db-migrate.test.ts     | 57 ++++++++++++++++++++++
 packages/core/src/chat-store.ts                    | 12 ++++-
 packages/core/src/chat-types.ts                    | 10 ++++
 packages/core/src/db.ts                            | 28 ++++++++++-
 packages/dashboard/app/api/__tests__/chat-rooms-api.test.ts       |  8 +--
 packages/dashboard/app/api/legacy.ts               |  4 +-
 packages/dashboard/app/components/ChatView.css     | 16 ++++++
 packages/dashboard/app/components/ChatView.tsx     | 29 ++++++++++-
 packages/dashboard/app/components/__tests__/ChatView.rooms.test.tsx   | 24 +++++++++
 packages/dashboard/app/hooks/__tests__/useChatRooms.test.ts       | 22 +++++++++
 packages/dashboard/app/hooks/useChatRooms.ts       | 16 ++++++
 packages/dashboard/src/__tests__/chat-room-routes.test.ts         | 26 ++++++++++
 packages/dashboard/src/__tests__/chat.rooms.test.ts     | 42 ++++++++++++++++
 packages/dashboard/src/chat.ts                     |  8 +++
 packages/dashboard/src/routes/register-chat-room-routes.ts        | 21 ++++++--
 19 files changed, 338 insertions(+), 16 deletions(-)

Fusion-Task-Id: FN-7909

Fusion-Task-Lineage: 2741eca9-5305-4f6c-81bf-ae644a9fe307

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-07-12 22:12:18 -07:00
parent 4ea5dd6739
commit daf3f15fd1
19 changed files with 338 additions and 16 deletions

View File

@@ -39,19 +39,19 @@ describe("chat room legacy API client", () => {
const fetchMock = vi.spyOn(globalThis, "fetch").mockImplementation(async () => jsonResponse({ success: true }));
await fetchChatRoom("room-1", "proj-1");
await createChatRoom({ name: "Engineering" }, "proj-1");
await updateChatRoom("room-1", { description: "desc" }, "proj-1");
await createChatRoom({ name: "Engineering", thinkingLevel: "high" }, "proj-1");
await updateChatRoom("room-1", { description: "desc", thinkingLevel: null }, "proj-1");
await deleteChatRoom("room-1", "proj-1");
expect((fetchMock.mock.calls[0] as [string])[0]).toContain("/api/chat/rooms/room-1?projectId=proj-1");
const [, createInit] = fetchMock.mock.calls[1] as [string, RequestInit];
expect(createInit.method).toBe("POST");
expect(createInit.body).toBe(JSON.stringify({ name: "Engineering", projectId: "proj-1" }));
expect(createInit.body).toBe(JSON.stringify({ name: "Engineering", thinkingLevel: "high", projectId: "proj-1" }));
const [, updateInit] = fetchMock.mock.calls[2] as [string, RequestInit];
expect(updateInit.method).toBe("PATCH");
expect(updateInit.body).toBe(JSON.stringify({ description: "desc" }));
expect(updateInit.body).toBe(JSON.stringify({ description: "desc", thinkingLevel: null }));
const [, deleteInit] = fetchMock.mock.calls[3] as [string, RequestInit];
expect(deleteInit.method).toBe("DELETE");

View File

@@ -10399,7 +10399,7 @@ export function fetchChatRoom(id: string, projectId?: string): Promise<ChatRoomR
}
export function createChatRoom(
input: { name: string; description?: string | null; createdBy?: string | null; memberAgentIds?: string[] },
input: { name: string; description?: string | null; createdBy?: string | null; memberAgentIds?: string[]; thinkingLevel?: string | null },
projectId?: string,
): Promise<ChatRoomResponse> {
const body = { ...input, ...(projectId ? { projectId } : {}) };
@@ -10411,7 +10411,7 @@ export function createChatRoom(
export function updateChatRoom(
id: string,
updates: { name?: string; description?: string | null; status?: "active" | "archived" },
updates: { name?: string; description?: string | null; status?: "active" | "archived"; thinkingLevel?: string | null },
projectId?: string,
): Promise<{ room: ChatRoom }> {
return api<{ room: ChatRoom }>(withProjectId(`/chat/rooms/${encodeURIComponent(id)}`, projectId), {