fix(bots): restore the #97008 session contracts on the rebuilt modules

createCanonicalChat sends follow_profile_config and ensureGroupChatSession
sends room_plumbing + follow_profile_config again, as main's plugin.js did
before the rebuild. Without them, bot sessions created by this branch fell
back to the server's legacy title heuristics (exact 'Bot Chat' title;
hidden + 'Group: ' prefix) — the exact dependence the explicit contracts
were introduced to replace. Contract-shape tests pin both params.
This commit is contained in:
Teknium
2026-08-28 05:11:09 -07:00
parent 387c73b19a
commit d22e8e4022
5 changed files with 49 additions and 3 deletions

View File

@@ -125,7 +125,15 @@ describe('the lazy row is materialized before anything else touches it', () => {
const { createCanonicalChat } = await loadModule()
await createCanonicalChat('alpha')
expect(created).toMatchObject({ hidden: true, title: 'Bot Chat' })
expect(created).toMatchObject({
hidden: true,
title: 'Bot Chat',
// The PR #97008 contract: the canonical Bot Chat's runtime always
// follows the profile's CURRENT config on resume — never the stored
// model/provider pin. Dropping this param silently regresses bots to
// the server's exact-title legacy fallback.
follow_profile_config: true
})
})
it('sends the one intro turn on New Bot creation (kickoff: true)', async () => {

View File

@@ -302,7 +302,14 @@ export function createCanonicalChat(
// plugin-owned. Core applies this via the generic `hidden` flag
// (deferred as pending_hidden until the row exists); older gateways
// ignore the unknown param and it stays visible.
hidden: true
hidden: true,
// Explicit contract (PR #97008): this session's runtime always follows
// the member profile's CURRENT config. Resume must NOT restore the
// stored model/provider pin from an old row — that left bot DMs stuck
// on a stale/dead provider after a profile switch. Older gateways
// ignore the unknown param; the server's exact-title backfill then
// covers the legacy path.
follow_profile_config: true
})
const sid = res?.stored_session_id

View File

@@ -30,6 +30,7 @@ export interface ScriptedMessage {
}
export interface ScriptedSession {
contracts?: { follow_profile_config: boolean; room_plumbing: boolean }
messages: ScriptedMessage[]
profile: string
runtime: string
@@ -219,6 +220,10 @@ export function createGroupGateway(options: GatewayOptions = {}): ScriptedGatewa
const title = String(params.title ?? '')
const session: ScriptedSession = {
contracts: {
follow_profile_config: params.follow_profile_config === true,
room_plumbing: params.room_plumbing === true
},
messages: [],
profile,
runtime: `rt-${profile}-${sequence}`,

View File

@@ -81,6 +81,26 @@ describe('session resolution', () => {
expect(room.gateway.sessions.get(String(fresh.stored))?.title).toBe('Group: r-abc')
})
it('creates member sessions with the room_plumbing + follow_profile_config contracts', async () => {
// The PR #97008 contracts: room member sessions always rebuild from the
// member profile's CURRENT config on resume, never a stale stored
// model/provider pin. Dropping either param silently regresses rooms to
// the server's hidden + "Group: " title legacy fallback.
const room = await loadRoom()
room.chat.updateGroupChat('Contract', current => {
current.roomId = 'r-contract'
return current
})
const handle = await room.turns.ensureGroupChatSession('Contract', { name: 'research', title: '' })
expect(room.gateway.sessions.get(String(handle.stored))?.contracts).toEqual({
follow_profile_config: true,
room_plumbing: true
})
})
it('mints fresh member sessions when a same-name group is recreated after disband', async () => {
const room = await loadRoom()
const member: GroupMember = { name: 'research', title: '' }

View File

@@ -198,7 +198,13 @@ export async function ensureGroupChatSession(group: string, member: GroupMember)
profile: member.name,
title,
// Room member sessions are plumbing — always hidden from the sidebar.
hidden: true
hidden: true,
// Explicit contracts (PR #97008): room plumbing sessions always rebuild
// from the member profile's CURRENT config on resume, never a stale
// stored model/provider pin. Older gateways ignore the unknown params;
// the server's hidden + "Group: " title fallback then covers legacy.
room_plumbing: true,
follow_profile_config: true
})) as { session_id?: string; stored_session_id?: string }
const stored = created?.stored_session_id || null