Skip to content

feat(ai): implement AI autocomplete - #8300

Merged
naman-bruno merged 2 commits into
usebruno:mainfrom
naman-bruno:feat/autocomplete
Jun 23, 2026
Merged

naman-bruno merged 2 commits into
usebruno:mainfrom
naman-bruno:feat/autocomplete

Conversation

@naman-bruno

@naman-bruno naman-bruno commented Jun 18, 2026 •

Copy link
Copy Markdown
Collaborator

Description

JIRA

Contribution Checklist:

  • I've used AI significantly to create this pull request
  • The pull request only addresses one issue or adds one feature.
  • The pull request does not introduce any breaking changes
  • I have added screenshots or gifs to help explain the change if applicable.
  • I have read the contribution guidelines.
  • Create an issue and link to the pull request.

Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.

Publishing to New Package Managers

Please see here for more information.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added AI-powered inline “ghost text” autocomplete to pre-request, post-response, and test editors (Tab to accept, Esc to dismiss, Cmd/Ctrl+\ to trigger).
    • Updated AI Preferences with a dedicated Autocomplete tab (Inline Autocomplete toggle, model selection, trigger mode with a debounced default).
    • Context-aware autocomplete now uses request details, variables, and related scripts to generate inline suggestions.
  • Improvements
    • Persisted autocomplete settings and disabled/dimmed controls when AI is off or no usable models/providers are available.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e1f50af4-1f25-4660-a5aa-e96b2b1531da

📥 Commits

Reviewing files that changed from the base of the PR and between a9ae605 and d2f0d5d.

📒 Files selected for processing (2)
  • packages/bruno-electron/src/index.js
  • packages/bruno-electron/src/store/preferences.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/bruno-electron/src/index.js
  • packages/bruno-electron/src/store/preferences.js

Walkthrough

Adds AI inline ghost-text autocomplete to Bruno's CodeMirror script editors. Extends preferences schema and Redux state with an autocomplete sub-object, adds a tabbed Autocomplete settings pane in AI Preferences, implements a CodeMirror 5 ghost-text engine with debounce/reuse/cache, adds Electron IPC and LLM prompt-building modules, and propagates item/scriptType props to all script editor call sites.

Changes

AI Ghost-Text Autocomplete

Layer / File(s) Summary
Autocomplete preferences schema and Redux state
packages/bruno-electron/src/store/preferences.js, packages/bruno-app/src/providers/ReduxStore/slices/app.js
Extends defaultPreferences.ai and preferencesSchema with a new autocomplete object containing enabled, model, and triggerMode fields. Mirrors shape in Redux app.js initial state.
AutocompletePane component
packages/bruno-app/src/components/Preferences/AI/AutocompletePane.js
New React component with TRIGGER_MODES constant, render-control logic deriving hasUsableModel/isInteractive/blockerMessage, settings card with toggle, model selector, trigger-mode pills with radio semantics, keymap help, and conditional dimmed/blocker display.
Tabbed AI Preferences UI
packages/bruno-app/src/components/Preferences/AI/index.js, packages/bruno-app/src/components/Preferences/AI/StyledWrapper.js
Refactors Preferences/AI into Configuration and Autocomplete tabs via activeTab state. Extends Formik initialValues and handleSave to persist new ai.autocomplete config. Adds usableModels memo filtering providers/models by enablement. Wires AutocompletePane handlers to Formik. Adds comprehensive .ai-tabs, .autocomplete-card, .trigger-pills, .model-select CSS.
Renderer-side AI IPC and context builder
packages/bruno-app/src/utils/ai/index.js
Exports aiAutocomplete(params) and cancelAiAutocomplete(requestId) IPC message wrappers. Implements buildAutocompleteContext({ item, collection, scriptType }) that assembles request context from item, extracts variable names with skipped keys and process.env, and retrieves up to 3 recent sibling scripts by type.
Electron prompt building and IPC registration
packages/bruno-electron/src/ipc/ai/autocomplete-prompts.js, packages/bruno-electron/src/index.js
Adds buildSystemPrompt(scriptType) with tailored instructions, formatting helpers for request/variable/sibling context sections, buildUserPrompt(...) constructing cursor-anchored code blocks, STOP_SEQUENCES for model cutoff, and cleanSuggestion(raw) to strip markdown/preambles. Registers registerAiAutocompleteIpc(mainWindow) in main process.
CodeMirror ghost-text engine
packages/bruno-app/src/utils/codemirror/aiGhostText.js, packages/bruno-app/src/components/CodeEditor/StyledWrapper.js
Implements setupAiAutocomplete(editor, options): per-editor WeakMap state, DOM widget rendering, local cache with trim-on-reuse, in-flight request snapshotting/cancellation, debounce/aggressive/manual trigger modes, Tab-accept/Esc-dismiss/Cmd+\ hotkeys, and full cleanup. Adds .cm-ghost-text-ai CSS styling.
CodeEditor Redux integration
packages/bruno-app/src/components/CodeEditor/index.js
Imports Redux useSelector and AI setup dependencies. CodeEditorWithPersistenceScope reads state.app.preferences?.ai and passes aiPreferences to CodeEditor. CodeEditor conditionally calls setupAiAutocomplete(...) in componentDidMount when scriptType is present and invokes cleanup in componentWillUnmount.
Script editor prop propagation
packages/bruno-app/src/components/RequestPane/Script/index.js, packages/bruno-app/src/components/RequestPane/Tests/index.js, packages/bruno-app/src/components/CollectionSettings/Script/index.js, packages/bruno-app/src/components/FolderSettings/Script/index.js
All script and test editors now receive item={item} and scriptType ("pre-request" / "post-response" / "tests") props to enable autocomplete context construction and request/variable collection.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CodeEditor
    participant aiGhostText as aiGhostText Engine
    participant ipcRenderer
    participant ElectronMain as Electron Main
    participant autocompletePrompts as autocomplete-prompts
    participant AIProvider as AI Provider

    User->>CodeEditor: types in script editor
    CodeEditor->>aiGhostText: onChange event
    aiGhostText->>aiGhostText: check local cache (instant reuse)
    aiGhostText->>ipcRenderer: aiAutocomplete(prefix, suffix, context, requestId)
    ipcRenderer->>ElectronMain: renderer:ai-autocomplete
    ElectronMain->>autocompletePrompts: buildSystemPrompt(scriptType)
    ElectronMain->>autocompletePrompts: formatRequestContext + formatVariableNames + formatSiblingScripts
    ElectronMain->>autocompletePrompts: buildUserPrompt(prefix, suffix, formatted)
    ElectronMain->>AIProvider: chat completion + STOP_SEQUENCES
    AIProvider-->>ElectronMain: raw text
    ElectronMain->>autocompletePrompts: cleanSuggestion(raw)
    ElectronMain-->>ipcRenderer: cleaned suggestion
    ipcRenderer-->>aiGhostText: suggestion text
    aiGhostText->>CodeEditor: render ghost-text widget at cursor
    User->>CodeEditor: Tab key
    CodeEditor->>aiGhostText: keydown Tab
    aiGhostText->>CodeEditor: insert suggestion, mark origin
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • usebruno/bruno#8048: Establishes foundational AI preferences and Redux store configuration that this PR extends with the new ai.autocomplete sub-object and corresponding settings UI.
  • usebruno/bruno#8178: Modifies the same AI preferences UI files that this PR further refactors with tabbed layout and the new AutocompletePane component.

Suggested reviewers

  • helloanoop
  • lohit-bruno
  • bijin-bruno
  • sid-bruno

Poem

✨ Ghost text whispers hints at every keystroke,
A faint promise only Tab can invoke.
Debounced, or eager—choose your pace,
Escape to dismiss, ⌘+\ for the race.
Context-aware suggestions drift on screen,
The editor becomes what it might have been. 🤖

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(ai): implement AI autocomplete' accurately describes the main change—adding AI autocomplete functionality across the codebase.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/bruno-app/src/components/Preferences/AI/AutocompletePane.js`:
- Around line 76-80: Add stable data-testid attributes to all interactive
elements in the AutocompletePane component to enable Playwright selectors.
Specifically, add a data-testid prop to the ToggleSwitch component shown in the
diff, and also add data-testid to the other interactive elements in the ranges
mentioned (101-107, 124-139). Use descriptive test IDs that clearly identify
each control's purpose, such as using naming patterns like
"autocomplete-enabled-toggle" or similar conventions that match the component's
functionality.

In `@packages/bruno-app/src/components/Preferences/AI/index.js`:
- Around line 145-165: Add `data-testid` attributes to the two tab button
elements in the AI preferences tab control. The first button that switches to
the 'config' tab (with aria-selected={activeTab === 'config'}) should have a
unique data-testid identifier, and the second button that switches to the
'autocomplete' tab (with aria-selected={activeTab === 'autocomplete'}) should
also have a unique data-testid identifier. These identifiers will allow
Playwright tests to reliably select and interact with these tab controls without
relying on brittle selectors.
- Around line 242-245: The enabled-provider check in the hasConfiguredProvider
block is using p.id to access formik.values.providers, but
formik.values.providers is keyed by Object.keys(status.providers) which may not
match p.id. Replace the Object.values(status.providers) iteration with
Object.entries(status.providers) or Object.keys(status.providers) to ensure the
keys used to access formik.values.providers match the actual structure of the
formik object, so that configured and enabled providers are correctly detected.

In `@packages/bruno-app/src/utils/ai/index.js`:
- Around line 84-107: The collectSiblingScripts function currently breaks from
the loop as soon as it reaches maxCount matching scripts, returning the first N
scripts found. To collect the last N scripts instead, remove the early break
condition that checks if out.length >= maxCount, and after the loop completes,
return only the last maxCount items from the out array using array slicing to
ensure the function returns the most recent scripts rather than the oldest ones.

In `@packages/bruno-app/src/utils/codemirror/aiGhostText.js`:
- Around line 296-307: In the onChange handler function, add immediate
cancellation of any in-flight autocomplete requests rather than deferring
cancellation until the next fetch cycle. Specifically, cancel the request
immediately when changeObj.origin is not '+ai-autocomplete' or when edit
conditions indicate a new fetch is needed, rather than waiting until
scheduleFetch is called. Additionally, apply the same immediate cancellation
logic to the blur event handler (around lines 318-320) to prevent stale requests
from continuing after blur. This ensures that provider calls are not wasted and
reduces stale-response races.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b3d463e5-b667-4086-81d2-068488b6e25f

📥 Commits

Reviewing files that changed from the base of the PR and between fab18d9 and bd106ab.

📒 Files selected for processing (16)
  • packages/bruno-app/src/components/CodeEditor/StyledWrapper.js
  • packages/bruno-app/src/components/CodeEditor/index.js
  • packages/bruno-app/src/components/CollectionSettings/Script/index.js
  • packages/bruno-app/src/components/FolderSettings/Script/index.js
  • packages/bruno-app/src/components/Preferences/AI/AutocompletePane.js
  • packages/bruno-app/src/components/Preferences/AI/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/AI/index.js
  • packages/bruno-app/src/components/RequestPane/Script/index.js
  • packages/bruno-app/src/components/RequestPane/Tests/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/app.js
  • packages/bruno-app/src/utils/ai/index.js
  • packages/bruno-app/src/utils/codemirror/aiGhostText.js
  • packages/bruno-electron/src/index.js
  • packages/bruno-electron/src/ipc/ai/autocomplete-prompts.js
  • packages/bruno-electron/src/ipc/ai/autocomplete.js
  • packages/bruno-electron/src/store/preferences.js

Comment thread packages/bruno-app/src/components/Preferences/AI/index.js
Comment thread packages/bruno-app/src/components/Preferences/AI/index.js
Comment thread packages/bruno-app/src/utils/ai/index.js
Comment thread packages/bruno-app/src/utils/codemirror/aiGhostText.js
Inline ghost-text autocomplete in script editors with three trigger modes
(aggressive / debounced / manual), per-feature model picker, and rich
context shipped to the model (request HTTP context, env/global/collection
variable names, last few sibling scripts of the same type).

- New IPC handler renderer:ai-autocomplete with backend LRU+TTL cache and
  abortable in-flight requests.
- CodeMirror 5 ghost-text engine wired into Pre-Request, Post-Response,
  Tests, Folder and Collection script editors.
- Preferences > AI is now a tabbed pane: Configuration + Autocomplete.

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
packages/bruno-app/src/components/Preferences/AI/index.js (1)

145-167: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Minor a11y enhancement: link tabs to panels with id/aria-controls.

The tab buttons lack aria-controls and the panels lack id attributes to properly associate them. This is optional but would improve screen reader navigation.

         <button
           type="button"
           role="tab"
           aria-selected={activeTab === 'config'}
+          aria-controls="ai-tabpanel-config"
           className={`ai-tab ${activeTab === 'config' ? 'active' : ''}`}
           onClick={() => setActiveTab('config')}
           data-testid="ai-tab-config"
         >
...
       {activeTab === 'config' && (
-        <div className="ai-tab-panel" role="tabpanel">
+        <div id="ai-tabpanel-config" className="ai-tab-panel" role="tabpanel" aria-labelledby="ai-tab-config">

Same pattern for the autocomplete tab/panel.

Also applies to: 176-177, 236-237

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/bruno-app/src/components/Preferences/AI/index.js` around lines 145 -
167, The tab buttons in the AI preferences component lack proper accessibility
associations with their content panels. Add an `aria-controls` attribute to each
tab button (the ones with role="tab" for 'config' and 'autocomplete' tabs) that
references the ID of its corresponding panel. Then add matching `id` attributes
to the panel container divs that display the tab content. For example, the
'config' tab button should have aria-controls pointing to the ID of the
configuration panel div, and the 'autocomplete' tab button should point to the
autocomplete panel. Apply this same pattern to any other tabs mentioned in the
related code sections referenced in the comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/bruno-app/src/components/Preferences/AI/index.js`:
- Around line 145-167: The tab buttons in the AI preferences component lack
proper accessibility associations with their content panels. Add an
`aria-controls` attribute to each tab button (the ones with role="tab" for
'config' and 'autocomplete' tabs) that references the ID of its corresponding
panel. Then add matching `id` attributes to the panel container divs that
display the tab content. For example, the 'config' tab button should have
aria-controls pointing to the ID of the configuration panel div, and the
'autocomplete' tab button should point to the autocomplete panel. Apply this
same pattern to any other tabs mentioned in the related code sections referenced
in the comment.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 432e4b42-bdab-4fe4-b035-f5f7aae9115a

📥 Commits

Reviewing files that changed from the base of the PR and between ff5748e and a9ae605.

📒 Files selected for processing (16)
  • packages/bruno-app/src/components/CodeEditor/StyledWrapper.js
  • packages/bruno-app/src/components/CodeEditor/index.js
  • packages/bruno-app/src/components/CollectionSettings/Script/index.js
  • packages/bruno-app/src/components/FolderSettings/Script/index.js
  • packages/bruno-app/src/components/Preferences/AI/AutocompletePane.js
  • packages/bruno-app/src/components/Preferences/AI/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/AI/index.js
  • packages/bruno-app/src/components/RequestPane/Script/index.js
  • packages/bruno-app/src/components/RequestPane/Tests/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/app.js
  • packages/bruno-app/src/utils/ai/index.js
  • packages/bruno-app/src/utils/codemirror/aiGhostText.js
  • packages/bruno-electron/src/index.js
  • packages/bruno-electron/src/ipc/ai/autocomplete-prompts.js
  • packages/bruno-electron/src/ipc/ai/autocomplete.js
  • packages/bruno-electron/src/store/preferences.js
✅ Files skipped from review due to trivial changes (3)
  • packages/bruno-app/src/providers/ReduxStore/slices/app.js
  • packages/bruno-app/src/components/Preferences/AI/StyledWrapper.js
  • packages/bruno-app/src/components/CodeEditor/StyledWrapper.js
🚧 Files skipped from review as they are similar to previous changes (10)
  • packages/bruno-electron/src/index.js
  • packages/bruno-app/src/components/CollectionSettings/Script/index.js
  • packages/bruno-app/src/components/FolderSettings/Script/index.js
  • packages/bruno-app/src/components/RequestPane/Tests/index.js
  • packages/bruno-app/src/components/CodeEditor/index.js
  • packages/bruno-electron/src/store/preferences.js
  • packages/bruno-app/src/utils/ai/index.js
  • packages/bruno-app/src/components/Preferences/AI/AutocompletePane.js
  • packages/bruno-electron/src/ipc/ai/autocomplete-prompts.js
  • packages/bruno-app/src/components/RequestPane/Script/index.js

@utkarsh-bruno utkarsh-bruno left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Quick question :
We use Esc to cancel the ghost suggestion. If i type "bru.", the hints dropdown would open up and if i have a trigger on ai auto suggestion, then the ghost suggestion would too.
Esc also cancels the method dropdown, I guess, so I am guessing it will now only cancel the ai suggestion and not remove the hints dropdown.

If that's intended behaviour, i think it should be fine.

Rest of it looks good to me.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants