Skip to content

improvement(tables): show error message tooltip on errored workflow and enrichment cells#5449

Merged
TheodoreSpeaks merged 1 commit into
stagingfrom
fix/table-error
Jul 7, 2026
Merged

improvement(tables): show error message tooltip on errored workflow and enrichment cells#5449
TheodoreSpeaks merged 1 commit into
stagingfrom
fix/table-error

Conversation

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator

Summary

  • Hovering the "Error" badge on a table cell now shows the underlying error message in a tooltip — for both workflow columns and enrichment columns
  • Block-level errors surface the per-block message (exec.blockErrors[blockId]); run-level errors surface exec.error (workflow not found, rate limit, enrichment billing errors, etc.)
  • UI-only change in cell-render.tsx — the messages were already persisted and hydrated on the grid read path, the renderer was just dropping them. Falls back to the plain badge when no message exists

Type of Change

  • Improvement

Testing

Tested manually; typecheck, lint, and check:api-validation:strict pass

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 6, 2026 10:50pm

Request Review

@cursor

cursor Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
UI-only change in cell rendering with no auth, data, or API impact; messages were already on execution metadata.

Overview
Workflow and enrichment table cells that show an Error badge now surface the stored failure text on hover instead of only the badge.

resolveCellRender threads block-level messages from exec.blockErrors[blockId] and run-level messages from exec.error into the block-error and error render kinds. CellRender wraps the badge in a tooltip when a message is present and keeps the previous badge-only UI when it is missing.

Reviewed by Cursor Bugbot for commit 4785802. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e8447c8. Configure here.

// reactable assistant turn: no copy/thumbs row beneath the card, whether
// the card is awaiting answers or collapsed to its recap.
const endsWithQuestion = trimmedContent.endsWith('</question>')
const showActions = phase === 'settled' && !endsWithQuestion && (message.content || hasAnyBlocks)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Question suffix hides message actions

Medium Severity

showActions is suppressed whenever assistant content ends with </question>, but that suffix can remain after the question card is dismissed or after an invalid tag is dropped at parse time. Copy and feedback controls then stay hidden even though no interactive question UI is shown.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e8447c8. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR delivers two improvements: (1) error tooltip display for table cells, surfacing exec.blockErrors[blockId] for block-level errors and exec.error for run-level failures in cell-render.tsx; and (2) a new interactive <question> special-tag feature in the chat system with question cards, multi-step wizard UX, transcript-paired answer hiding, and round-trip parse/format helpers. Additional copilot tool catalog and metric entries (run_code, search, query_user_table, search_knowledge_base) are also registered.

  • The cell-render change correctly threads error messages through CellRenderKind and adds a tooltip wrapper; the null check on kind.message covers error (nullable) while block-error always has a non-empty message.
  • The QuestionDisplay component (478 lines) introduces a stateful wizard that renders answered cards from transcript data, suppressing the paired user bubble in the virtual list to avoid duplicate content.
  • Supporting changes add new tool catalog entries, metrics, and icons required by the question and code-execution features.

Confidence Score: 4/5

Safe to merge; the tooltip change in cell-render.tsx is minimal and correct, and the question card feature is well-tested. Two non-blocking concerns around prompt-newline parsing and the virtual list slot for hidden rows are worth a follow-up.

The cell-render change is small and correct — error messages are properly threaded through the type and the null check correctly handles the nullable exec.error field. The question card addition is larger and well-covered by new tests, but the parseQuestionAnswerMessage parser assumes prompts never contain newlines (nothing rejects them), which would silently break transcript pairing. The virtual list hidden-row rendering leaves an unsized slot that resolves via ResizeObserver, potentially producing a brief layout flash on history load.

question.tsx (prompt-newline edge case) and mothership-chat.tsx (virtual list hidden row sizing)

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/cell-render.tsx Core PR change: adds message to block-error and error kinds and wraps the badge in a tooltip when a message is present. Logic is correct — block-error always supplies a non-empty string (guarded by the if (blockError) check), and error may be null.
apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/question/question.tsx New 478-line QuestionDisplay component with single/multi-select wizard, transcript-paired recap, and format/parse helpers. Prompt newline handling in parseQuestionAnswerMessage is a minor edge case.
apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx Adds questionPairing memo to match assistant question cards with user answer messages and hides paired user rows in the virtual list; the endsWithQuestion check suppresses the copy/thumbs action row.
apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx Adds full question tag parsing with strict validation (type, prompt, options), catch-all option stripping, and normalization of single-object bodies to arrays.
apps/sim/lib/copilot/generated/tool-catalog-v1.ts Adds new ToolCatalogEntry entries for run_code, search, query_user_table, and search_knowledge_base; removes deprecated research/user_memory entries.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[resolveCellRender] --> B{workflowGroupId?}
    B -- yes --> C{blockError exists?}
    C -- yes --> D[block-error with message]
    C -- no --> E{exec.status?}
    E -- error --> F[error with exec.error]
    E -- other --> G[other kinds]
    D --> H[CellRender switch]
    F --> H
    H --> I{kind.message truthy?}
    I -- no --> J[StatusBadge plain]
    I -- yes --> K[Tooltip wrapping StatusBadge]
    L[messages loop] --> M{assistant has question tag?}
    M -- yes --> N{next msg is user reply?}
    N -- yes --> O[parseLastQuestionTag]
    O --> P[parseQuestionAnswerMessage]
    P -- matched --> Q[store answers, hide user bubble]
    P -- no match --> R[show normally]
    N -- no --> R
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[resolveCellRender] --> B{workflowGroupId?}
    B -- yes --> C{blockError exists?}
    C -- yes --> D[block-error with message]
    C -- no --> E{exec.status?}
    E -- error --> F[error with exec.error]
    E -- other --> G[other kinds]
    D --> H[CellRender switch]
    F --> H
    H --> I{kind.message truthy?}
    I -- no --> J[StatusBadge plain]
    I -- yes --> K[Tooltip wrapping StatusBadge]
    L[messages loop] --> M{assistant has question tag?}
    M -- yes --> N{next msg is user reply?}
    N -- yes --> O[parseLastQuestionTag]
    O --> P[parseQuestionAnswerMessage]
    P -- matched --> Q[store answers, hide user bubble]
    P -- no match --> R[show normally]
    N -- no --> R
Loading

Comments Outside Diff (1)

  1. apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx, line 1228-1237 (link)

    P2 Hidden user row leaves a sized slot in the virtual list

    When questionPairing.hiddenUserByIndex[index] is true the inner content renders null, but the outer virtual-list container div (with its measureElement ref and absolute translateY position) still exists in the DOM. On the first paint the virtual list will have estimated a non-zero height for that slot. The ResizeObserver will then detect the collapsed div and reflow — but this two-phase settle can produce a brief visible gap above or below the collapsed row on initial load of a conversation that has past question/answer pairs.

    An alternative is to filter hidden messages out of the rendered list (not just rendering null inside them) so the virtual list never allocates a slot for them at all.

Reviews (1): Last reviewed commit: "improvement(tables): show error message ..." | Re-trigger Greptile

Comment on lines +202 to +224
const selections = [...selectedByStep]
selections[step] = [label]
setSelectedByStep(selections)
const customs = [...customByStep]
customs[step] = ''
setCustomByStep(customs)
setFreeText('')
finishStep(selections, customs)
}

const handleMultiToggle = (label: string) => {
const selections = [...selectedByStep]
const current = selections[step] ?? []
selections[step] = current.includes(label)
? current.filter((l) => l !== label)
: [...current, label]
setSelectedByStep(selections)
}

/** multi_select confirm: commits selections and/or typed text, then advances. */
const submitMultiStep = () => {
finishStep(selectedByStep, commitCustom())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Prompt newlines break round-trip parsing

formatQuestionAnswerMessage serialises each question as ${q.prompt} — ${answer} joined by \n, and parseQuestionAnswerMessage reconstitutes by splitting on \n and checking lines.length === questions.length. If an agent supplies a prompt that itself contains a newline (nothing in isQuestionItem rejects them), the serialised string has extra \n characters, lines.length exceeds questions.length, and parseQuestionAnswerMessage returns null. The paired user message is not hidden and the answered-card recap is never shown — the question card stays in its active state on reload, which is misleading.

A one-line guard in isQuestionItem (value.prompt.includes('\n')) is enough to reject such prompts at parse time and keep the contract safe.

Comment on lines +296 to +306
/**
* Parses a `<question>` tag body. Accepts a single question object or a
* non-empty array of them; single objects are normalized to a one-element
* array so the renderer only handles the array shape.
*/
/**
* Extracts the last complete `<question>` tag payload from raw message
* content. Used by the chat list to pair an assistant question card with the
* user message that answered it.
*/
export function parseLastQuestionTag(content: string): QuestionTagData | null {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 The double JSDoc block here is a copy-paste artifact — the first /**...*/ comment describes parseLastQuestionTag but was left hanging when parseQuestionTagBody was added immediately before it. Only one doc comment should precede each function.

Suggested change
/**
* Parses a `<question>` tag body. Accepts a single question object or a
* non-empty array of them; single objects are normalized to a one-element
* array so the renderer only handles the array shape.
*/
/**
* Extracts the last complete `<question>` tag payload from raw message
* content. Used by the chat list to pair an assistant question card with the
* user message that answered it.
*/
export function parseLastQuestionTag(content: string): QuestionTagData | null {
/**
* Extracts the last complete `<question>` tag payload from raw message
* content. Used by the chat list to pair an assistant question card with the
* user message that answered it.
*/
export function parseLastQuestionTag(content: string): QuestionTagData | null {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@TheodoreSpeaks TheodoreSpeaks merged commit f111de3 into staging Jul 7, 2026
15 checks passed
@TheodoreSpeaks TheodoreSpeaks deleted the fix/table-error branch July 7, 2026 00:04
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