Skip to content

Add direct and AI-assisted command insertion modes#136

Open
MUFFANUJ wants to merge 12 commits intojupyterlab:mainfrom
MUFFANUJ:insertCommand
Open

Add direct and AI-assisted command insertion modes#136
MUFFANUJ wants to merge 12 commits intojupyterlab:mainfrom
MUFFANUJ:insertCommand

Conversation

@MUFFANUJ
Copy link
Copy Markdown
Member

@MUFFANUJ MUFFANUJ commented Apr 1, 2026

closes #106

This update adds an insertion dropdown for commands so users can choose the flow they want. In Insert mode, clicking + adds the command right at the current cursor position for a fast manual action. In AI mode, it does not insert immediately; it opens the AI chat and pre-fills a prompt so the user can review or adjust before sending. This gives both a quick, direct option and a guided AI option in the same UI.

@MUFFANUJ MUFFANUJ added the enhancement New feature or request label Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

Binder

Preview Lab Notebook v7
Binder Binder Binder Notebook v7
JupyterLite JupyterLite JupyterLite Notebook v7
👈 Launch a Binder on branch MUFFANUJ/plugin-playground/insertCommand

@jupyterlab jupyterlab deleted a comment from github-actions bot Apr 1, 2026
@MUFFANUJ MUFFANUJ closed this Apr 1, 2026
@github-project-automation github-project-automation bot moved this from Todo to Done in CFP '25 tracking Apr 1, 2026
@MUFFANUJ MUFFANUJ reopened this Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

Preview environments for this pull request:

Preview Lab Notebook v7
Binder Binder Binder Notebook v7
JupyterLite JupyterLite JupyterLite Notebook v7

@MUFFANUJ
Copy link
Copy Markdown
Member Author

MUFFANUJ commented Apr 1, 2026

The bot comments looks better now :)

@MUFFANUJ MUFFANUJ marked this pull request as ready for review April 1, 2026 21:57
Comment on lines +2318 to +2363
await this.app.commands.execute(JUPYTERLITE_AI_OPEN_CHAT_COMMAND, {
area: 'side'
});
this.app.shell.activateById(JUPYTERLITE_AI_CHAT_PANEL_ID);

const inputModel = this._requireJupyterLiteAIChatInputModel();
inputModel.value = prompt;
inputModel.focus();
}

private _requireJupyterLiteAIChatInputModel(): {
value: string;
focus: () => void;
} {
const sideWidgets = [
...Array.from(this.app.shell.widgets('left')),
...Array.from(this.app.shell.widgets('right'))
];
const chatPanel = sideWidgets.find(
widget => widget.id === JUPYTERLITE_AI_CHAT_PANEL_ID
) as
| {
current?: {
model?: { input?: unknown };
};
}
| undefined;
if (!chatPanel) {
throw new Error(
`${JUPYTERLITE_AI_INSTALL_HINT} Missing panel: "${JUPYTERLITE_AI_CHAT_PANEL_ID}".`
);
}

const candidate = chatPanel.current?.model?.input;
if (
candidate &&
typeof candidate === 'object' &&
'value' in candidate &&
typeof candidate.value === 'string' &&
'focus' in candidate &&
typeof candidate.focus === 'function'
) {
return candidate as { value: string; focus: () => void };
}
throw new Error(JUPYTERLITE_AI_PROVIDER_SETUP_HINT);
}
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.

Hmm, user may have already opened the chat inthe main area widget.

Could this be replaced by jupyter-chat public API? It looks like there is a tracker, there should be a way to do it. If not, we should open an issue in jupyter-chat or jupyterlite/ai (or both) asking how to pre-populate chat prompt from a third-party extension.

https://jupyter-chat.readthedocs.io/en/latest/developers/developing_extensions/using-chat-extension.html

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.

This is what I mean

Screencast.From.2026-04-02.11-25-15.mp4

but it may not be easy to find the chat that user wants. In any case, trying is worth while.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

we should open an issue in jupyter-chat or jupyterlite/ai (or both) asking how to pre-populate chat prompt from a third-party extension.

I tried searching it but couldnt find it, i will be opening a issue there for the discussion

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I have opened an issue in jupterlite/ai for the same jupyterlite/ai#307

@krassowski
Copy link
Copy Markdown
Member

I think we should make the dropdown button narrower, closer to the +:

image

and maybe add some shared outline to both buttons on hover so that more obviously feel like a part of the same UI element?

It might be worth thinking about AI + icon that would be the same size as the one without AI. Not sure how to achieve that.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a split “+” action for command IDs in the Plugin Playground sidebar, letting users either insert app.commands.execute('<id>'); directly at the editor cursor or open JupyterLite AI chat with a prefilled prompt to guide insertion in context.

Changes:

  • Introduces a command insertion split-button UI (Insert vs AI prompt) and persists the default mode via a new setting.
  • Implements direct cursor insertion plus AI chat prompt prefilling (via @jupyter/chat tracker + JupyterLite AI open-chat command).
  • Expands AST-based source utilities to better detect/ensure activate(app: JupyterFrontEnd, …) context and to group imports; adds/updates UI integration tests accordingly.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/index.ts Adds command insertion flows (direct + AI prompt), setting persistence, editor gating, and chat integration via IChatTracker.
src/token-sidebar.tsx Adds split insert button + dropdown menu for command insertion mode selection.
src/token-insertion.ts Enhances import insertion (group into existing imports) and adds helpers to detect/ensure activate() app parameter context.
schema/plugin.json Adds commandInsertDefaultMode setting (insert / ai).
style/base.css Styles the split-button and AI marker icon for command insertion.
ui-tests/tests/plugin-playground.spec.ts Adds UI tests for command insertion at cursor and AI prompt prefilling; updates token import assertions to allow grouped imports.
package.json Adds dependency on @jupyter/chat for IChatTracker.
yarn.lock Lockfile updates reflecting new dependency graph.
README.md Documents the new command insert modes and the persisted setting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

window.clearTimeout(this._copiedTimer);
this._copiedTimer = null;
}
this._commandInsertMenu.dispose();
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

TokenSidebar.dispose() disposes the Menu but not the associated CommandRegistry (_commandInsertMenuCommands). Since CommandRegistry is disposable and may hold signal connections, it should also be disposed to avoid leaking listeners when the sidebar widget is disposed/recreated.

Suggested change
this._commandInsertMenu.dispose();
this._commandInsertMenu.dispose();
this._commandInsertMenuCommands.dispose();

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Insert app.command.execute(<command-id>) when user clicks + on command?

3 participants