Skip to content

fix(web): preserve failed inactive send prompts#657

Open
oodavy41 wants to merge 1 commit into
tiann:mainfrom
oodavy41:fix/failed-send-preserve-prompt
Open

fix(web): preserve failed inactive send prompts#657
oodavy41 wants to merge 1 commit into
tiann:mainfrom
oodavy41:fix/failed-send-preserve-prompt

Conversation

@oodavy41
Copy link
Copy Markdown
Contributor

Summary

Preserve the user’s prompt when sending to an inactive/invalid session fails during session resolution/resume.

Previously, if resolveSessionId failed before the send mutation started, the composer had already cleared the input, so a 500/502 resume/send failure could make the user’s prompt disappear with no visible recovery path.

Changes

  • On resolveSessionId failure before send, append a failed optimistic user bubble containing the original prompt.
  • Keep the prompt visible/copyable/retryable instead of losing it.
  • Preserve scheduledAt and attachments in the failed bubble metadata/content.
  • Update retry behavior so failed preserved prompts re-run resolveSessionId before sending.
  • Restore failed status if retry-time resolution fails.
  • Add regression coverage for:
    • failed resolve preserving a prompt bubble;
    • retry resolving an inactive session before sending;
    • scheduled retry still preserving scheduledAt.

Notes

Known pre-existing limitation: retrying a failed bubble does not currently re-send attachments. This PR preserves attachments visually in the failed bubble but does not change the broader retry attachment behavior.

Validation

  • git diff --check origin/main..HEAD
  • bun typecheck
  • bun --cwd web test src/hooks/mutations/useSendMessage.test.tsx
  • env -u HAPI_CLI_EXECUTABLE bun run test

Full suite passed.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • [Major] Retried preserved prompts drop attachments — resolve failure now creates a failed bubble with attachments, but the new retry path calls mutation.mutate without carrying those attachments forward. api.sendMessage therefore receives undefined for attachments, so a preserved image/file prompt retries as text-only; attachment-only preserved prompts also remain non-retryable because the retry guard rejects empty originalText. Evidence web/src/hooks/mutations/useSendMessage.ts:226.
    Suggested fix:
    const message = findMessageByLocalId(sessionId, localId)
    if (!message) return false
    
    const content = message.content
    const userContent = content
        && typeof content === 'object'
        && 'role' in content
        && (content as { role?: unknown }).role === 'user'
        && 'content' in content
        ? (content as { content?: unknown }).content
        : undefined
    const attachments = userContent
        && typeof userContent === 'object'
        && 'attachments' in userContent
        ? (userContent as { attachments?: AttachmentMetadata[] }).attachments
        : undefined
    const originalText = message.originalText ?? ''
    if (!originalText && !attachments?.length) return false
    
    mutation.mutate({
        sessionId: targetSessionId,
        text: originalText,
        localId,
        createdAt: message.createdAt,
        attachments,
        scheduledAt: message.scheduledAt ?? null,
    })

Questions

  • None.

Summary

  • Review mode: initial
  • One regression found in the new preserved-prompt retry path. Add coverage for text+attachment and attachment-only preserved resolve failures so retry behavior matches the bubble the user sees.

Testing

  • Not run (automation): bun --cwd web test src/hooks/mutations/useSendMessage.test.tsx failed here because bun is not on PATH (/bin/bash: bun: command not found).

HAPI Bot

}
}

mutation.mutate({
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MAJOR] Retrying a prompt preserved by the new resolve-failure path drops its attachments. createOptimisticMessage now stores attachments in the failed bubble, but this retry mutation does not pass them back to api.sendMessage, so image/file prompts get retried as text-only; attachment-only prompts are still rejected by the originalText guard.

Suggested fix:

const message = findMessageByLocalId(sessionId, localId)
if (!message) return false

const content = message.content
const userContent = content
    && typeof content === 'object'
    && 'role' in content
    && (content as { role?: unknown }).role === 'user'
    && 'content' in content
    ? (content as { content?: unknown }).content
    : undefined
const attachments = userContent
    && typeof userContent === 'object'
    && 'attachments' in userContent
    ? (userContent as { attachments?: AttachmentMetadata[] }).attachments
    : undefined
const originalText = message.originalText ?? ''
if (!originalText && !attachments?.length) return false

mutation.mutate({
    sessionId: targetSessionId,
    text: originalText,
    localId,
    createdAt: message.createdAt,
    attachments,
    scheduledAt: message.scheduledAt ?? null,
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant