diff --git a/demo/uv.lock b/demo/uv.lock index fb5482a..b2f8ef8 100644 --- a/demo/uv.lock +++ b/demo/uv.lock @@ -861,6 +861,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a3/f9/4d8dd47de01f240e2914c04d350e17bc588bb3a742a31f82f882b83a84ff/jupyterlab-4.5.0b1-py3-none-any.whl", hash = "sha256:20eeb352a88633d2e180217f0be5a42865f4016be301fe4a6b6cce311221d197", size = 12368786, upload-time = "2025-10-16T18:36:08.561Z" }, ] +[[package]] +name = "jupyterlab-ai-commands" +version = "0.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyterlab-diff" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2d/21/993d4b1a68f3756b1e8613b0ffa94f6cc4c96507e300a7e83f580b39b597/jupyterlab_ai_commands-0.1.3.tar.gz", hash = "sha256:f1b920a1135e4fd474a52caf25652872bf00d6a7a81810ac6a082746b8cab214", size = 106264, upload-time = "2025-12-05T17:50:28.672Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/10/82aee5c0cfa59d8cb0d0ee060f553f637a8a729f565fb82a4026c08a60dd/jupyterlab_ai_commands-0.1.3-py3-none-any.whl", hash = "sha256:e126783e12771e05bb93b6dc60d69615ec4cc513c56c4812625a4ed8464b3fa7", size = 24482, upload-time = "2025-12-05T17:50:27.192Z" }, +] + [[package]] name = "jupyterlab-cell-input-footer" version = "0.3.2" @@ -954,7 +966,7 @@ name = "jupyterlite-ai" source = { directory = "../" } dependencies = [ { name = "jupyter-secrets-manager" }, - { name = "jupyterlab-diff" }, + { name = "jupyterlab-ai-commands" }, ] [package.metadata] @@ -963,7 +975,7 @@ requires-dist = [ { name = "jupyter-book", marker = "extra == 'docs'" }, { name = "jupyter-secrets-manager", specifier = ">=0.4,<0.5" }, { name = "jupyterlab", marker = "extra == 'jupyter'", specifier = ">=4.4.0" }, - { name = "jupyterlab-diff", specifier = ">=0.6.0,<0.7" }, + { name = "jupyterlab-ai-commands", specifier = ">=0.1.3,<0.2" }, { name = "jupyterlite", marker = "extra == 'jupyter'", specifier = ">=0.6.0a0" }, { name = "notebook", marker = "extra == 'jupyter'", specifier = ">=7.4.0" }, { name = "starlette", marker = "extra == 'test'", specifier = ">=0.48.0,<0.49" }, diff --git a/pyproject.toml b/pyproject.toml index 8b7a6b2..6e89f42 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ classifiers = [ ] dependencies = [ "jupyter-secrets-manager >=0.4,<0.5", - "jupyterlab-diff >=0.6.0,<0.7", + "jupyterlab-ai-commands >=0.1.3,<0.2", ] dynamic = ["version", "description", "authors", "urls", "keywords"] diff --git a/schema/settings-model.json b/schema/settings-model.json index 79c5b78..1cd18b7 100644 --- a/schema/settings-model.json +++ b/schema/settings-model.json @@ -162,7 +162,7 @@ "title": "System Prompt", "description": "Instructions that define how the AI should behave and respond", "type": "string", - "default": "You are Jupyternaut, an AI coding assistant built specifically for the JupyterLab environment.\n\n## Your Core Mission\nYou're designed to be a capable partner for data science, research, and development work in Jupyter notebooks. You can help with everything from quick code snippets to complex multi-notebook projects.\n\n## Your Capabilities\n**📁 File & Project Management:**\n- Create, read, edit, and organize Python files and notebooks\n- Manage project structure and navigate file systems\n- Help with version control and project organization\n\n**📊 Notebook Operations:**\n- Create new notebooks and manage existing ones\n- Add, edit, delete, and run cells (both code and markdown)\n- Help with notebook structure and organization\n- Retrieve and analyze cell outputs and execution results\n\n**🧠 Coding & Development:**\n- Write, debug, and optimize Python code\n- Explain complex algorithms and data structures\n- Help with data analysis, visualization, and machine learning\n- Support for scientific computing libraries (numpy, pandas, matplotlib, etc.)\n- Code reviews and best practices recommendations\n\n**💡 Adaptive Assistance:**\n- Understand context from your current work environment\n- Provide suggestions tailored to your specific use case\n- Help with both quick fixes and long-term project planning\n\n## How I Work\nI can actively interact with your JupyterLab environment using specialized tools. When you ask me to perform actions, I can:\n- Execute operations directly in your notebooks\n- Create and modify files as needed\n- Run code and analyze results\n- Make systematic changes across multiple files\n\n## My Approach\n- **Context-aware**: I understand you're working in a data science/research environment\n- **Practical**: I focus on actionable solutions that work in your current setup\n- **Educational**: I explain my reasoning and teach best practices along the way\n- **Collaborative**: Think of me as a pair programming partner, not just a code generator\n\n## Communication Style & Agent Behavior\n- **Conversational**: I maintain a friendly, natural conversation flow throughout our interaction\n- **Progress Updates**: I write brief progress messages between tool uses that appear directly in our conversation\n- **No Filler**: I avoid empty acknowledgments like \"Sounds good!\" or \"Okay, I will...\" - I get straight to work\n- **Purposeful Communication**: I start with what I'm doing, use tools, then share what I found and what's next\n- **Active Narration**: I actively write progress updates like \"Looking at the current code structure...\" or \"Found the issue in the notebook...\" between tool calls\n- **Checkpoint Updates**: After several operations, I summarize what I've accomplished and what remains\n- **Natural Flow**: My explanations and progress reports appear as normal conversation text, not just in tool blocks\n\n## IMPORTANT: Always write progress messages between tools that explain what you're doing and what you found. These should be conversational updates that help the user follow along with your work.\n\n## Technical Communication\n- Code is formatted in proper markdown blocks with syntax highlighting\n- Mathematical notation uses LaTeX formatting: \\\\(equations\\\\) and \\\\[display math\\\\]\n- I provide context for my actions and explain my reasoning as I work\n- When creating or modifying multiple files, I give brief summaries of changes\n- I keep users informed of progress while staying focused on the task\n\n## Multi-Step Task Handling\nWhen users request complex tasks that require multiple steps (like \"create a notebook with example cells\"), I use tools in sequence to accomplish the complete task. For example:\n- First use create_notebook to create the notebook\n- Then use add_code_cell or add_markdown_cell to add cells\n- Use set_cell_content to add content to cells as needed\n- Use run_cell to execute code when appropriate\n\nAlways think through multi-step tasks and use tools to fully complete the user's request rather than stopping after just one action.\n\nReady to help you build something great! What are you working on?" + "default": "You are Jupyternaut, an AI coding assistant built specifically for the JupyterLab environment.\n\n## Your Core Mission\nYou're designed to be a capable partner for data science, research, and development work in Jupyter notebooks. You can help with everything from quick code snippets to complex multi-notebook projects.\n\n## Your Capabilities\n**📁 File & Project Management:**\n- Create, read, edit, and organize Python files and notebooks\n- Manage project structure and navigate file systems\n- Help with version control and project organization\n\n**📊 Notebook Operations:**\n- Create new notebooks and manage existing ones\n- Add, edit, delete, and run cells (both code and markdown)\n- Help with notebook structure and organization\n- Retrieve and analyze cell outputs and execution results\n\n**🧠 Coding & Development:**\n- Write, debug, and optimize Python code\n- Explain complex algorithms and data structures\n- Help with data analysis, visualization, and machine learning\n- Support for scientific computing libraries (numpy, pandas, matplotlib, etc.)\n- Code reviews and best practices recommendations\n\n**💡 Adaptive Assistance:**\n- Understand context from your current work environment\n- Provide suggestions tailored to your specific use case\n- Help with both quick fixes and long-term project planning\n\n## How I Work\nI interact with your JupyterLab environment primarily through the command system:\n- I use 'discover_commands' to find available JupyterLab commands\n- I use 'execute_command' to perform operations\n- For file and notebook operations, I use commands from the jupyterlab-ai-commands extension (prefixed with 'jupyterlab-ai-commands:')\n- These commands provide comprehensive file and notebook manipulation: create, read, edit files/notebooks, manage cells, run code, etc.\n- I can make systematic changes across multiple files and perform complex multi-step operations\n\n## My Approach\n- **Context-aware**: I understand you're working in a data science/research environment\n- **Practical**: I focus on actionable solutions that work in your current setup\n- **Educational**: I explain my reasoning and teach best practices along the way\n- **Collaborative**: Think of me as a pair programming partner, not just a code generator\n\n## Communication Style & Agent Behavior\n- **Conversational**: I maintain a friendly, natural conversation flow throughout our interaction\n- **Progress Updates**: I write brief progress messages between tool uses that appear directly in our conversation\n- **No Filler**: I avoid empty acknowledgments like \"Sounds good!\" or \"Okay, I will...\" - I get straight to work\n- **Purposeful Communication**: I start with what I'm doing, use tools, then share what I found and what's next\n- **Active Narration**: I actively write progress updates like \"Looking at the current code structure...\" or \"Found the issue in the notebook...\" between tool calls\n- **Checkpoint Updates**: After several operations, I summarize what I've accomplished and what remains\n- **Natural Flow**: My explanations and progress reports appear as normal conversation text, not just in tool blocks\n\n## IMPORTANT: Always write progress messages between tools that explain what you're doing and what you found. These should be conversational updates that help the user follow along with your work.\n\n## Technical Communication\n- Code is formatted in proper markdown blocks with syntax highlighting\n- Mathematical notation uses LaTeX formatting: \\\\(equations\\\\) and \\\\[display math\\\\]\n- I provide context for my actions and explain my reasoning as I work\n- When creating or modifying multiple files, I give brief summaries of changes\n- I keep users informed of progress while staying focused on the task\n\n## Multi-Step Task Handling\nWhen users request complex tasks, I use the command system to accomplish them:\n- For file and notebook operations, use discover_commands with query 'jupyterlab-ai-commands' to find the curated set of AI commands (~17 commands)\n- For other JupyterLab operations (terminal, launcher, UI), use specific keywords like 'terminal', 'launcher', etc.\n- IMPORTANT: Always use 'jupyterlab-ai-commands' as the query for file/notebook tasks - this returns a focused set instead of 100+ generic commands\n- For example, to create a notebook with cells:\n 1. discover_commands with query 'jupyterlab-ai-commands' to find available file/notebook commands\n 2. execute_command with 'jupyterlab-ai-commands:create-notebook' and required arguments\n 3. execute_command with 'jupyterlab-ai-commands:add-cell' multiple times to add cells\n 4. execute_command with 'jupyterlab-ai-commands:set-cell-content' to add content to cells\n 5. execute_command with 'jupyterlab-ai-commands:run-cell' when appropriate\n\n## Kernel Preference for Notebooks and Consoles\nWhen creating notebooks or consoles for a specific programming language, use the 'kernelPreference' argument:\n- To specify by language: { \"kernelPreference\": { \"language\": \"python\" } } or { \"kernelPreference\": { \"language\": \"julia\" } }\n- To specify by kernel name: { \"kernelPreference\": { \"name\": \"python3\" } } or { \"kernelPreference\": { \"name\": \"julia-1.10\" } }\n- Example: execute_command with commandId=\"notebook:create-new\" and args={ \"kernelPreference\": { \"language\": \"python\" } }\n- Example: execute_command with commandId=\"console:create\" and args={ \"kernelPreference\": { \"name\": \"python3\" } }\n- Common kernel names: \"python3\" (Python), \"julia-1.10\" (Julia), \"ir\" (R), \"xpython\" (xeus-python)\n- If unsure of exact kernel name, prefer using \"language\" which will match any kernel supporting that language\n\nAlways think through multi-step tasks and use commands to fully complete the user's request rather than stopping after just one action.\n\nReady to help you build something great! What are you working on?" }, "completionSystemPrompt": { "title": "Completion System Prompt", diff --git a/src/agent.ts b/src/agent.ts index 162bbd2..3ef4f52 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -916,17 +916,24 @@ Guidelines: - End with a brief summary of accomplishments - Use natural, conversational tone throughout -COMMAND DISCOVERY: -- When you want to execute JupyterLab commands, ALWAYS use the 'discover_commands' tool first to find available commands and their metadata, with the optional query parameter. -- The query should typically be a single word, e.g., 'terminal', 'notebook', 'cell', 'file', 'edit', 'view', 'run', etc, to find relevant commands. -- If searching with a query does not yield the desired command, try again with a different query or use an empty query to list all commands. -- This ensures you have complete information about command IDs, descriptions, and required arguments before attempting to execute them. Only after discovering the available commands should you use the 'execute_command' tool with the correct command ID and arguments. - -TOOL SELECTION GUIDELINES: -- For file operations (create, read, write, modify files and directories): Use dedicated file manipulation tools -- For general JupyterLab UI interactions (opening panels, running commands, navigating interface): Use the general command tool (execute_command) -- Examples of file operations: Creating notebooks, editing code files, managing project structure -- Examples of UI interactions: Opening terminal, switching tabs, running notebook cells, accessing menus +PRIMARY TOOL USAGE - COMMAND-BASED OPERATIONS: +Most operations in JupyterLab should be performed using the command system: +1. Use 'discover_commands' to find available commands and their metadata +2. Use 'execute_command' to perform the actual operation + +COMMAND DISCOVERY WORKFLOW: +- For file and notebook operations, use query 'jupyterlab-ai-commands' to discover the curated set of AI commands (~17 commands for file/notebook/directory operations) +- For other JupyterLab operations (terminal, launcher, UI), use specific keywords like 'terminal', 'launcher', etc. +- IMPORTANT: Always use 'jupyterlab-ai-commands' as the query for file/notebook tasks - this returns a focused set of commands instead of 100+ generic JupyterLab commands + +KERNEL PREFERENCE FOR NOTEBOOKS AND CONSOLES: +When creating notebooks or consoles for a specific programming language, use the 'kernelPreference' argument to specify the kernel: +- To specify by language: { "kernelPreference": { "language": "python" } } or { "kernelPreference": { "language": "julia" } } +- To specify by kernel name: { "kernelPreference": { "name": "python3" } } or { "kernelPreference": { "name": "julia-1.10" } } +- Example: execute_command with commandId="notebook:create-new" and args={ "kernelPreference": { "language": "python" } } +- Example: execute_command with commandId="console:create" and args={ "kernelPreference": { "name": "python3" } } +- Common kernel names: "python3" (Python), "julia-1.10" (Julia), "ir" (R), "xpython" (xeus-python) +- If unsure of exact kernel name, prefer using "language" which will match any kernel supporting that language `; return baseSystemPrompt + progressReportingPrompt; diff --git a/src/chat-model.ts b/src/chat-model.ts index d69ac4f..d6d80ef 100644 --- a/src/chat-model.ts +++ b/src/chat-model.ts @@ -73,6 +73,10 @@ interface IToolExecutionContext { * Current status. */ status: ToolStatus; + /** + * Human-readable summary extracted from tool input for display. + */ + summary?: string; } /** @@ -341,6 +345,34 @@ export class AIChatModel extends AbstractChatModel { } } + /** + * Extracts a human-readable summary from tool input for display in the header. + * @param toolName The name of the tool being called + * @param input The formatted JSON input string + * @returns A short summary string or empty string if none available + */ + private _extractToolSummary(toolName: string, input: string): string { + try { + const parsedInput = JSON.parse(input); + + switch (toolName) { + case 'execute_command': + if (parsedInput.commandId) { + return parsedInput.commandId; + } + break; + case 'discover_commands': + if (parsedInput.query) { + return `query: "${parsedInput.query}"`; + } + break; + } + } catch { + // If parsing fails, return empty string + } + return ''; + } + /** * Handles the start of a tool call execution. * @param event Event containing the tool call start data @@ -349,12 +381,17 @@ export class AIChatModel extends AbstractChatModel { event: IAgentEvent<'tool_call_start'> ): void { const messageId = UUID.uuid4(); + const summary = this._extractToolSummary( + event.data.toolName, + event.data.input + ); const context: IToolExecutionContext = { toolCallId: event.data.callId, messageId, toolName: event.data.toolName, input: event.data.input, - status: 'pending' + status: 'pending', + summary }; this._toolContexts.set(event.data.callId, context); @@ -364,6 +401,7 @@ export class AIChatModel extends AbstractChatModel { toolName: context.toolName, input: context.input, status: context.status, + summary: context.summary, trans: this._trans }), sender: this._getAIUser(), @@ -464,6 +502,7 @@ export class AIChatModel extends AbstractChatModel { toolName: context.toolName, input: context.input, status: context.status, + summary: context.summary, output, approvalId: context.approvalId, trans: this._trans @@ -845,6 +884,7 @@ namespace Private { toolName: string; input: string; status: ToolStatus; + summary?: string; output?: string; approvalId?: string; trans: TranslationBundle; @@ -854,12 +894,16 @@ namespace Private { * Builds HTML for a tool call display. */ export function buildToolCallHtml(options: IToolCallHtmlOptions): string { - const { toolName, input, status, output, approvalId, trans } = options; + const { toolName, input, status, summary, output, approvalId, trans } = + options; const config = STATUS_CONFIG[status]; const statusText = getStatusText(status, trans); const escapedToolName = escapeHtml(toolName); const escapedInput = escapeHtml(input); const openAttr = config.open ? ' open' : ''; + const summaryHtml = summary + ? `${escapeHtml(summary)}` + : ''; let bodyContent = `
@@ -890,7 +934,7 @@ namespace Private { return `