Skip to content

[ZEPPELIN-6557] Add history-based inline completion to the new UI editor - #5339

Merged
tbonelee merged 9 commits into
apache:masterfrom
voidmatcha:monaco-upgrade-spike
Aug 24, 2026
Merged

[ZEPPELIN-6557] Add history-based inline completion to the new UI editor#5339
tbonelee merged 9 commits into
apache:masterfrom
voidmatcha:monaco-upgrade-spike

Conversation

@voidmatcha

@voidmatcha voidmatcha commented Jul 25, 2026

Copy link
Copy Markdown
Member

What is this PR for?

Adds ghost-text inline completion to the new UI notebook editor. It is the first, LLM-free, opt-in step of ZEPPELIN-6329 (AI autocomplete). InlineCompletionService registers a Monaco inline-completions provider for python/scala: when a line elsewhere in the note starts with the current line's text before the cursor, it offers the remainder as ghost text (the current cell first, then other paragraphs of the same language). There is no server call and no API key — everything is in-browser, in-memory string matching, in the spirit of fish/JupyterLab history completion.

The feature is off by default and only active with ?aiInlineComplete=true; with the flag off there is no behaviour change and no provider is registered.

This requires bumping Monaco 0.31.1 → 0.52.2 (and monaco-editor-webpack-plugin 7.0.1 → 7.1.1) for the stabilised inline-completion API. The only source compile change is editor.getAction() becoming nullable. Monaco 0.55/0.56 currently break the webpack plugin (unresolved new contrib modules), so 0.52.x is the upper bound.

The ?aiInlineComplete=true flag is an experimental gate for this purely-local tier. When the server-backed LLM tier lands (follow-up sub-task), inline completion will be promoted to a proper, persisted user setting.

What type of PR is it?

Improvement

Todos

  • Bump Monaco to 0.52.2 + webpack plugin, npm ci lock verified
  • InlineCompletionService (opt-in, history-based ghost text)
  • Update find-widget e2e selectors for Monaco 0.52 DOM changes

What is the Jira issue?

ZEPPELIN-6557 (sub-task of ZEPPELIN-6329)

How should this be tested?

  1. cd zeppelin-web-angular && npm run build && npm run lint
  2. ng serve, log in, open a note with a python paragraph (append ?aiInlineComplete=true to the URL)
  3. In one paragraph type users = spark.read.parquet("/data/users"); in another, start typing users = spark.read. — the remainder appears as grey ghost text; press Tab to accept
  4. With the flag off (default), confirm there is no ghost text and behaviour is unchanged

Monaco 0.52.2 changed the find-widget DOM (.button.next/title.codicon-find-next-match/aria-label), so the selectors in e2e/models/editor-search-page.ts were updated accordingly. Tab only accepts a suggestion while one is visible; otherwise it indents normally (built-in Monaco behaviour, not overridden).

Screenshots (if appropriate)

real-typing-demo.mp4

Questions:

  • Does the license files need to update? — No
  • Is there breaking changes for older versions? — No
  • Does this needs documentation? — No

@voidmatcha
voidmatcha force-pushed the monaco-upgrade-spike branch 2 times, most recently from 6ebfb7e to 50ef4e8 Compare August 2, 2026 03:10
@voidmatcha
voidmatcha force-pushed the monaco-upgrade-spike branch 2 times, most recently from c0e1378 to ff0d988 Compare August 7, 2026 04:02
jongyoul
jongyoul previously approved these changes Aug 9, 2026

@jongyoul jongyoul left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM. I hope we could expand this feature to use AI sooner. 👍

@voidmatcha
voidmatcha force-pushed the monaco-upgrade-spike branch from 6812528 to f4baa47 Compare August 23, 2026 11:47
@voidmatcha
voidmatcha force-pushed the monaco-upgrade-spike branch 2 times, most recently from 57edab0 to 9c92321 Compare August 23, 2026 15:26
@voidmatcha

Copy link
Copy Markdown
Member Author

@tbonelee I stabilized the inline completion E2E by verifying blur through an outside click because Monaco handles the second ESC differently in Firefox and WebKit. Instead of relying on ghost-text-specific DOM, the test polls .view-line until the suggested text is rendered, then checks focus is preserved after the first ESC and released after the outside click.

await expect(inputArea).toBeFocused();

// Firefox and WebKit handle Monaco's second Escape differently from Chromium.
await page.locator('body').click({ position: { x: 5, y: 5 } });

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.

Could we make the test name more explicit first? preserves focus on the first Escape implies a second step, but the body no longer has a second Escape.

Just to confirm the intent: was this meant to verify that the editor blurs on the second Escape? If so, the last commit seems to change direction a little. Clicking outside blurs through native browser behaviour, so I think it never goes through the Escape command or the when clause (!inlineSuggestionVisible). If clicking outside already blurred the editor before this PR, wouldn't the assertion pass regardless of the change here? That feels slightly off from what the test set out to verify.

@voidmatcha
voidmatcha force-pushed the monaco-upgrade-spike branch from 9c92321 to 6cc9d16 Compare August 24, 2026 02:27
@voidmatcha
voidmatcha force-pushed the monaco-upgrade-spike branch from 6cc9d16 to ecd7fbe Compare August 24, 2026 03:05
@tbonelee
tbonelee merged commit cb219f6 into apache:master Aug 24, 2026
18 checks passed
@tbonelee

Copy link
Copy Markdown
Contributor

Merged into master

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.

3 participants