Fix ask answer handoff and OAuth warnings

This commit is contained in:
Marco Beretta 2026-08-08 02:23:09 +02:00
parent aefd3c9d14
commit e01eac1892
No known key found for this signature in database
GPG key ID: D918033D8E74CC11
4 changed files with 31 additions and 9 deletions

View file

@ -38,7 +38,7 @@ function hasFailedOutput(output: unknown): boolean {
return typeof output === 'string' && isError(output);
}
function hasPendingAuth(part: TMessageContentParts, isSubmitting: boolean): boolean {
function hasPendingAuth(part: TMessageContentParts): boolean {
if (part.type !== ContentTypes.TOOL_CALL) {
return false;
}
@ -50,10 +50,7 @@ function hasPendingAuth(part: TMessageContentParts, isSubmitting: boolean): bool
const progress = standardToolCall.progress ?? 0.1;
return (
typeof standardToolCall.auth === 'string' &&
standardToolCall.auth.length > 0 &&
progress < 1 &&
(isSubmitting || hasFailedOutput(standardToolCall.output))
typeof standardToolCall.auth === 'string' && standardToolCall.auth.length > 0 && progress < 1
);
}
@ -442,8 +439,8 @@ export default function ToolCallGroup({
[toolMetadata, isSubmitting],
);
const hasPendingAuthRequest = useMemo(
() => parts.some(({ part }) => hasPendingAuth(part, isSubmitting)),
[parts, isSubmitting],
() => parts.some(({ part }) => hasPendingAuth(part)),
[parts],
);
useEffect(() => {

View file

@ -310,6 +310,17 @@ describe('ToolCallGroup image hoisting', () => {
expect(screen.getAllByText('Only allow sites you trust')).toHaveLength(1);
});
it('keeps the trust warning for a persisted incomplete authentication call', () => {
renderGroup({
...baseProps,
parts: [{ part: makeAuthPart('auth-persisted', 'zapier'), idx: 0 }],
lastContentIdx: 0,
renderPart: () => <ToolAuthWarning key="auth-persisted" />,
});
expect(screen.getByText('Only allow sites you trust')).toBeInTheDocument();
});
it('does not render a shared trust warning for completed authentication calls', () => {
renderGroup({
...baseProps,

View file

@ -141,7 +141,7 @@ describe('useAskAnswerMode', () => {
expect(result.current.liveAsk).toBeNull();
});
it('carries the composer answer into shared card state when collapsed', () => {
it('moves the composer answer into the card and clears it when drafts are disabled', () => {
mockUseGetMessages.mockReturnValue({ data: liveAsk });
const { result } = renderHook(() => useAskAnswerMode('conversation-1'));
@ -151,6 +151,17 @@ describe('useAskAnswerMode', () => {
actionId: 'a1',
text: 'answer from A',
});
expect(mockResetComposer).toHaveBeenCalledTimes(1);
});
it('lets draft handoff restore the conversation composer when drafts are enabled', () => {
mockSaveDrafts = true;
mockUseGetMessages.mockReturnValue({ data: liveAsk });
const { result } = renderHook(() => useAskAnswerMode('conversation-1'));
act(() => result.current.collapse());
expect(mockResetComposer).not.toHaveBeenCalled();
});
it('restores the card answer into the composer when drafts are disabled', () => {

View file

@ -187,12 +187,15 @@ export default function useAskAnswerMode(conversationId?: string | null) {
const composerAnswer = formContext?.getValues('text') ?? answerText;
morphTransition(() => {
setAnswerDraft({ actionId: liveAsk.actionId, text: composerAnswer });
if (!saveDrafts) {
formContext?.reset();
}
setCollapsedIds((prev) =>
prev.includes(liveAsk.actionId) ? prev : [...prev, liveAsk.actionId],
);
});
}
}, [liveAsk, formContext, answerText, setAnswerDraft, setCollapsedIds]);
}, [liveAsk, formContext, answerText, saveDrafts, setAnswerDraft, setCollapsedIds]);
const expand = useCallback(() => {
if (liveAsk) {