Skip to content

feat(ai-chat): Codiff-style AI walkthroughs for generated SQL#1948

Open
datlechin wants to merge 5 commits into
mainfrom
feat/ai-sql-walkthroughs
Open

feat(ai-chat): Codiff-style AI walkthroughs for generated SQL#1948
datlechin wants to merge 5 commits into
mainfrom
feat/ai-sql-walkthroughs

Conversation

@datlechin

Copy link
Copy Markdown
Member

Closes #1945.

AI Explain, Optimize, and Fix Error now answer with a reviewable walkthrough in the chat panel instead of plain markdown, so a user can inspect an AI SQL change before trusting it.

What you get

  • Before/after SQL diff for Optimize and Fix, with a Unified / Split toggle (persisted per block). Explain shows the query with the steps anchored to it.
  • Numbered steps with a one-line reason and an importance tag (Critical / Change / Context). Expand a step to see the exact lines it refers to; Jump to lines scrolls to and highlights them.
  • Ask about a step sends a follow-up question that stays anchored to that step.
  • Apply to Editor replaces the editor content with the suggested SQL after a confirmation. Nothing is applied automatically.

Design

The AI writes only the narrative (the rewritten afterSQL plus ordered steps). The app computes the diff itself from the original query, so the diff always reflects the real change and a model cannot show a diff that does not exist.

Structured output travels as a fenced JSON envelope parsed out of the streamed text, not tool calling. This works on every provider including the local ones (Ollama, llama.cpp, MLX), and degrades to plain markdown when a model ignores the format: the fence is stripped so no raw JSON shows, and the response renders as normal text.

Native and HIG details: semantic red/green with +/- gutter markers (never color alone), DisclosureGroup steps, reduce-motion gated highlight, VoiceOver status on diff rows, confirm-before-apply per Apple's Generative AI guidance. Anchors that fall out of range render no highlight rather than pointing at the wrong line.

Structure

Three commits:

  1. refactor(datagrid) extracts the line-diff engine (DiffComputer/DiffPair) out of FileConflictDiffSheet into Core/Diff/SqlDiff.swift, adding unified-diff output and SQL normalization. The conflict sheet consumes it unchanged.
  2. feat(ai-chat) adds the .sqlWalkthrough chat block (additive wire Codable, old conversations still decode) and AIChatWalkthroughBlockView, and encodes the walkthrough as proposed-SQL text in every provider's history so follow-ups keep context.
  3. feat(ai-chat) adds the envelope parser, the three walkthrough prompt templates, and the view-model wiring, plus CHANGELOG and docs.

Tests

New unit tests: envelope parsing (well-formed, code-fenced, no-close-fence, malformed, no-fence, null afterSQL, unique step ids, stripFence), diff extraction parity and unified diff, SQL normalization, anchor validity (in-range / out-of-range / nil), and .sqlWalkthrough wire round-trip plus legacy decode. UI automation is deferred: the flow depends on non-deterministic AI responses and needs a mock provider injection point.

Verified locally: build succeeds, and all four new suites pass.

Scope note

In-editor cross-highlighting (highlighting the anchored lines in the main editor, not just the in-chat diff) is intentionally left out of this first version to keep the panel decoupled from editor state. Worth a follow-up.

@mintlify

mintlify Bot commented Jul 22, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
TablePro 🟢 Ready View Preview Jul 22, 2026, 5:07 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 72988d7bb1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

: String(localized: "Replace the editor content with the suggested SQL"))
}
.alert(String(localized: "Apply suggested SQL?"), isPresented: $showApplyConfirmation) {
Button(String(localized: "Apply")) { actions?.insertQueryFromAI(afterSQL) }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Replace the active query when applying a walkthrough

For the normal Optimize/Fix flow, the selected editor tab already contains the query being reviewed. insertQueryFromAI only mutates an empty selected query tab and otherwise opens a new query tab (MainContentCoordinator.swift:1017-1036), so confirming this action does not perform the replacement promised by the button and confirmation text; it leaves the original editor content unchanged.

Useful? React with 👍 / 👎.

Comment on lines +229 to +231
func resolveWalkthroughIfNeeded(id: UUID) {
guard let beforeSQL = pendingWalkthroughBeforeSQL else { return }
pendingWalkthroughBeforeSQL = nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Retain walkthrough context for regeneration and retry

A successful walkthrough clears the only stored beforeSQL here, but regenerate() deletes that assistant turn and restarts streaming without restoring it; likewise the error path clears it before retry(). The hidden prompt still instructs the model to emit the envelope, but resolveWalkthroughIfNeeded then returns immediately, so regenerated/retried Explain, Optimize, and Fix responses display their raw JSON instead of the walkthrough UI.

Useful? React with 👍 / 👎.

Comment on lines +448 to +450
private func activateAnchor(_ anchor: SqlWalkthroughAnchor) {
activeAnchor = anchor
scrollTarget = unifiedScrollTarget(for: anchor)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use split-row targets when the split diff is selected

When users select Split and press “Jump to lines,” this always calculates an ID from the unified diff. Split rows are identified by their DiffPair index, while unified IDs gain an extra entry for each changed pair, so after any prior replacement the target either scrolls to a different row or does not exist in the split view. The highlighted lines are correct, but the advertised jump action is not.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 22d7563d4e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +155 to +157
func sendWithWalkthroughContext(prompt: String, beforeSQL: String) {
pendingWalkthroughBeforeSQL = beforeSQL
sendWithContext(prompt: prompt)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Clear walkthrough state when the request does not start

When a walkthrough command cannot start—for example, no provider is configured, the connection policy is never, or preflight rejects an oversized prompt—this state remains set because none of those early exits clears it. The next ordinary chat message then receives the walkthrough system directive and is parsed against the stale SQL, so a normal response can be rendered as an unrelated SQL walkthrough.

Useful? React with 👍 / 👎.

Comment on lines +124 to +125
private func unifiedDiff(before: [String], after: [String]) -> some View {
let lines = Array(DiffComputer.computeUnified(before: before, after: after).prefix(Self.maxDiffLines))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Count rendered unified diff rows when truncating

For a query with 500 changed lines, computeUnified emits 1,000 display rows (a removal and addition per change), but this prefixes the result at 500 while the footer compares against max(before.count, after.count), also 500. Consequently the entire added half of the diff is silently hidden with no truncation notice, preventing users from reviewing the proposed SQL before applying it.

Useful? React with 👍 / 👎.

@mintlify

mintlify Bot commented Jul 22, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
TablePro 🟡 Building Jul 22, 2026, 5:05 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

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.

Consider Codiff-style AI walkthroughs for generated SQL

1 participant