fix(desktop): forward optional composer handlers through the latest-actions adapter
latestChatActions rebuilds the ChatView handler bag field by field, so an optional handler added to ChatActions but not to the adapter is silently dropped before it reaches ChatView. Live CDP probe on a built Desktop: the wiring controller had onAttachPastedText, ChatView received undefined, and a 4,500-char paste stayed inline. onAttachPrCommentUrl and onSteerHidden (already on main) were dropped the same way on the main chat surface; the session-tile path passes them directly and was unaffected. Forward all three via latestOptional and pin the class with one invariant test: every handler present on the actions bag is present on the adapted bag (red on the previous adapter).
This commit is contained in:
@@ -11,6 +11,8 @@ function makeChatActions(): ChatActions {
|
||||
onAddUrl: vi.fn(),
|
||||
onAttachDroppedItems: vi.fn(),
|
||||
onAttachImageBlob: vi.fn(),
|
||||
onAttachPastedText: vi.fn(),
|
||||
onAttachPrCommentUrl: vi.fn(),
|
||||
onBranchInNewChat: vi.fn(),
|
||||
onCancel: vi.fn(),
|
||||
onDeleteSelectedSession: vi.fn(),
|
||||
@@ -25,6 +27,7 @@ function makeChatActions(): ChatActions {
|
||||
onRestoreToMessage: vi.fn(),
|
||||
onRetryResume: vi.fn(),
|
||||
onSteer: vi.fn(),
|
||||
onSteerHidden: vi.fn(),
|
||||
onSubmit: vi.fn(),
|
||||
onThreadMessagesChange: vi.fn(),
|
||||
onToggleSelectedPin: vi.fn(),
|
||||
@@ -49,6 +52,15 @@ function makeSidebarActions(): SidebarActions {
|
||||
}
|
||||
|
||||
describe('latestActions adapters', () => {
|
||||
it('forwards every present handler — an optional one the adapter forgets never reaches ChatView', () => {
|
||||
const actions = makeChatActions()
|
||||
const adapted = latestChatActions(actions)
|
||||
|
||||
for (const key of Object.keys(actions) as (keyof ChatActions)[]) {
|
||||
expect(typeof adapted[key], key).toBe('function')
|
||||
}
|
||||
})
|
||||
|
||||
it('dereferences the latest steer handler from a stable actions object', async () => {
|
||||
const staleSteer = vi.fn(async () => false)
|
||||
const latestSteer = vi.fn(async () => true)
|
||||
|
||||
@@ -34,6 +34,8 @@ export function latestChatActions(actions: ChatActions): ChatActions {
|
||||
onAddUrl: (...args) => actions.onAddUrl(...args),
|
||||
onAttachDroppedItems: (...args) => actions.onAttachDroppedItems(...args),
|
||||
onAttachImageBlob: (...args) => actions.onAttachImageBlob(...args),
|
||||
onAttachPastedText: latestOptional(() => actions.onAttachPastedText),
|
||||
onAttachPrCommentUrl: latestOptional(() => actions.onAttachPrCommentUrl),
|
||||
onBranchInNewChat: latestOptional(() => actions.onBranchInNewChat),
|
||||
onCancel: (...args) => actions.onCancel(...args),
|
||||
onDeleteSelectedSession: (...args) => actions.onDeleteSelectedSession(...args),
|
||||
@@ -48,6 +50,7 @@ export function latestChatActions(actions: ChatActions): ChatActions {
|
||||
onRestoreToMessage: latestOptional(() => actions.onRestoreToMessage),
|
||||
onRetryResume: (...args) => actions.onRetryResume(...args),
|
||||
onSteer: (...args) => actions.onSteer(...args),
|
||||
onSteerHidden: latestOptional(() => actions.onSteerHidden),
|
||||
onSubmit: (...args) => actions.onSubmit(...args),
|
||||
onThreadMessagesChange: (...args) => actions.onThreadMessagesChange(...args),
|
||||
onToggleSelectedPin: (...args) => actions.onToggleSelectedPin(...args),
|
||||
|
||||
Reference in New Issue
Block a user