notebook-intelligence 5.0.1__tar.gz → 5.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- notebook_intelligence-5.1.0/.editorconfig +22 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/.gitignore +10 -1
- notebook_intelligence-5.1.0/.husky/_/.gitignore +1 -0
- notebook_intelligence-5.1.0/.husky/_/applypatch-msg +2 -0
- notebook_intelligence-5.1.0/.husky/_/commit-msg +2 -0
- notebook_intelligence-5.1.0/.husky/_/h +22 -0
- notebook_intelligence-5.1.0/.husky/_/husky.sh +9 -0
- notebook_intelligence-5.1.0/.husky/_/post-applypatch +2 -0
- notebook_intelligence-5.1.0/.husky/_/post-checkout +2 -0
- notebook_intelligence-5.1.0/.husky/_/post-commit +2 -0
- notebook_intelligence-5.1.0/.husky/_/post-merge +2 -0
- notebook_intelligence-5.1.0/.husky/_/post-rewrite +2 -0
- notebook_intelligence-5.1.0/.husky/_/pre-applypatch +2 -0
- notebook_intelligence-5.1.0/.husky/_/pre-auto-gc +2 -0
- notebook_intelligence-5.1.0/.husky/_/pre-commit +2 -0
- notebook_intelligence-5.1.0/.husky/_/pre-merge-commit +2 -0
- notebook_intelligence-5.1.0/.husky/_/pre-push +2 -0
- notebook_intelligence-5.1.0/.husky/_/pre-rebase +2 -0
- notebook_intelligence-5.1.0/.husky/_/prepare-commit-msg +2 -0
- notebook_intelligence-5.1.0/.husky/pre-commit +1 -0
- notebook_intelligence-5.1.0/.vscode/extensions.json +8 -0
- notebook_intelligence-5.1.0/.vscode/settings.json +34 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/CHANGELOG.md +46 -1
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/CONTRIBUTING.md +10 -1
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/PKG-INFO +9 -2
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/PRIVACY.md +1 -1
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/README.md +7 -1
- notebook_intelligence-5.1.0/benchmarks/claude_perf/README.md +64 -0
- notebook_intelligence-5.1.0/benchmarks/claude_perf/bench_nbi_ws.py +148 -0
- notebook_intelligence-5.1.0/benchmarks/claude_perf/bench_runner.py +226 -0
- notebook_intelligence-5.1.0/benchmarks/claude_perf/bench_terminal.py +102 -0
- notebook_intelligence-5.1.0/benchmarks/claude_perf/prompts.py +26 -0
- notebook_intelligence-5.1.0/benchmarks/claude_perf/report.py +124 -0
- notebook_intelligence-5.1.0/benchmarks/claude_perf/stats.py +34 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/docs/admin-guide.md +42 -4
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/docs/troubleshooting.md +19 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/_version.py +1 -1
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/ai_service_manager.py +13 -1
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/api.py +25 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/built_in_toolsets.py +106 -6
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/claude.py +234 -67
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/claude_mcp_manager.py +24 -1
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/extension.py +158 -3
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/github_copilot.py +103 -2
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/package.json +8 -2
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/schemas/@plmbr/notebook-intelligence/package.json.orig +7 -1
- notebook_intelligence-5.1.0/notebook_intelligence/labextension/static/208.4c4b9a3414346968118a.js +1 -0
- notebook_intelligence-5.0.1/notebook_intelligence/labextension/static/537.02c6edab4e3a352bb107.js → notebook_intelligence-5.1.0/notebook_intelligence/labextension/static/537.4541361a520b995bd8e6.js +1 -1
- notebook_intelligence-5.1.0/notebook_intelligence/labextension/static/728.12e4f642352152ad6499.js +1 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/editor.worker.js +3 -3
- notebook_intelligence-5.1.0/notebook_intelligence/labextension/static/remoteEntry.b320c63c1e6526880d72.js +1 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/mcp_manager.py +25 -1
- notebook_intelligence-5.1.0/notebook_intelligence/mcp_policy.py +118 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/util.py +104 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/package.json +7 -1
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/pyproject.toml +6 -0
- notebook_intelligence-5.1.0/tests/test_builtin_file_read.py +132 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_claude_mcp_manager.py +108 -0
- notebook_intelligence-5.1.0/tests/test_claude_tool_humanizer.py +208 -0
- notebook_intelligence-5.1.0/tests/test_default_password_refusal.py +205 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_image_context.py +15 -1
- notebook_intelligence-5.1.0/tests/test_mcp_manager_command_allowlist.py +241 -0
- notebook_intelligence-5.1.0/tests/test_mcp_policy.py +132 -0
- notebook_intelligence-5.1.0/tests/test_process_tree_teardown.py +189 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_websocket_handler_integration.py +80 -14
- notebook_intelligence-5.1.0/tests/ts/tool-call-card.test.tsx +180 -0
- notebook_intelligence-5.1.0/tests/ts/tool-call-group.test.tsx +107 -0
- notebook_intelligence-5.1.0/tests/ts/tool-call-stream.test.ts +111 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/utils.test.ts +9 -3
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/yarn.lock +355 -4
- notebook_intelligence-5.0.1/notebook_intelligence/labextension/static/703.b2a16c3edc281d79d13a.js +0 -1
- notebook_intelligence-5.0.1/notebook_intelligence/labextension/static/728.cae98e1655349e508971.js +0 -1
- notebook_intelligence-5.0.1/notebook_intelligence/labextension/static/remoteEntry.e77a2554241f4d36341c.js +0 -1
- notebook_intelligence-5.0.1/tests/test_claude_tool_humanizer.py +0 -68
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/.copier-answers.yml +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/.prettierignore +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/.yarnrc.yml +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/LICENSE +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/RELEASE.md +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/SECURITY.md +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/docs/admin-tour-config.md +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/docs/rulesets.md +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/docs/skills.md +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/install.json +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/jest.config.js +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/jupyter-config/server-config/notebook_intelligence.json +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/__init__.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/_claude_cli.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/base_chat_participant.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/cell_output.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/claude_sessions.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/config.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/context_factory.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/feature_flags.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/github_copilot_chat_participant.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/schemas/@plmbr/notebook-intelligence/plugin.json +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/196.da0c2020639344d5c419.js +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/1b55f12eca93ba6743e7.ttf +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/327.47473c656f6c27efa1dc.js +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/327.47473c656f6c27efa1dc.js.LICENSE.txt +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/631.f00d05d8305a78ec8301.js +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/671.1b1a53f5f75bff82950b.js +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/694.2ebfa9714301d9260bf0.js +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/745.f63673e66e02301096f4.js +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/745.f63673e66e02301096f4.js.LICENSE.txt +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/977.b917f705175326af0e5d.js +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/be02dcbf2787b0b29ec8.module.wasm +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/e589c9ba04e3e5a90081.module.wasm +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/editor.worker.js.LICENSE.txt +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/style.js +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/labextension/static/third-party-licenses.json +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/llm_providers/github_copilot_llm_provider.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/llm_providers/litellm_compatible_llm_provider.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/llm_providers/ollama_llm_provider.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/llm_providers/openai_compatible_llm_provider.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/mcp_client.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/mcp_config_validation.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/plugin_manager.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/prompts.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/rule_injector.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/rule_manager.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/ruleset.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/skill_github_import.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/skill_manager.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/skill_manifest.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/skill_reconciler.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/skillset.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/notebook_intelligence/tour_config.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/schema/plugin.json +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/setup.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/conftest.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/fixtures/rules/01-test-global.md +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/fixtures/rules/02-test-security.md +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/fixtures/rules/03-invalid-rule.md +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/fixtures/rules/modes/agent/01-test-production.md +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/fixtures/rules/modes/ask/01-test-exploration.md +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/fixtures/rules/modes/inline-chat/01-test-quick.md +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_ai_service_manager_integration.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_api_hygiene.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_base_chat_participant_integration.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_builtin_toolset_cwd_sandbox.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_cell_output.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_cell_output_features_response.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_claude_client.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_claude_models.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_claude_sessions.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_claude_sessions_handler.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_claude_system_prompt.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_claude_tool_path_sandbox.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_coding_agent_launchers.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_config_atomic_save.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_config_integration.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_context_factory.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_end_to_end_rule_integration.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_feature_flags.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_feedback.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_file_upload.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_github_copilot_llm_provider.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_github_copilot_user_data_mode.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_mcp_client_shim.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_mcp_config_validation.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_mcp_manager.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_models.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_openai_compatible_llm_provider.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_plugin_manager.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_policy_gate.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_redact_process_secrets.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_response_emitter.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_rule_auto_reload.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_rule_injector.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_rule_manager.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_safe_anchor_uri.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_skill_fetch_redirects.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_skill_github_import.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_skill_manager.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_skill_manifest.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_skill_reconciler.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_skills_handlers.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_tour_config.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_ws_callback_handler_leak.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/test_ws_handler_auth.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/__mocks__/jupyterlab-apputils.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/__mocks__/jupyterlab-filebrowser.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/__mocks__/svg.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/__mocks__/tiktoken.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/ask-user-question.test.tsx +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/cell-output-bundle.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/cell-output-features.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/cell-output-toolbar.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/chat-progress-feedback.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/checkbox.test.tsx +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/choose-workspace-directory.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/claude-mcp-paste.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/coding-agent-launchers.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/launcher-picker.test.tsx +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/markdown-renderer.test.tsx +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/mcp-util.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/notebook-generation.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/open-file-refresh-watcher.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/plugins-panel.test.tsx +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/safe-anchor.test.tsx +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/setup.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/skill-wire-format.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/task-target-notebook.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/terminal-drag.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/tour-config.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/tour-events.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/tour-overlay.test.tsx +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/tour-state.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/tsconfig.json +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tests/ts/workspace-skips.test.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/tsconfig.json +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/.eslintrc.js +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/README.md +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/jupyter_server_test_config.py +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/package.json +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/playwright.config.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/tests/cell-output.spec.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/tests/chat-sidebar.spec.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/tests/claude-mcp-patch.spec.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/tests/extension.spec.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/tests/helpers.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/tests/launcher.spec.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/tests/notebook-toolbar.spec.ts +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/tsconfig.json +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/ui-tests/yarn.lock +0 -0
- {notebook_intelligence-5.0.1 → notebook_intelligence-5.1.0}/webpack.config.js +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# EditorConfig (https://editorconfig.org) keeps basic whitespace consistent
|
|
2
|
+
# across editors. It complements Prettier rather than replacing it: Prettier
|
|
3
|
+
# still owns the canonical formatting enforced by `jlpm lint:check`.
|
|
4
|
+
root = true
|
|
5
|
+
|
|
6
|
+
[*]
|
|
7
|
+
charset = utf-8
|
|
8
|
+
end_of_line = lf
|
|
9
|
+
insert_final_newline = true
|
|
10
|
+
trim_trailing_whitespace = true
|
|
11
|
+
indent_style = space
|
|
12
|
+
indent_size = 2
|
|
13
|
+
|
|
14
|
+
# Trailing whitespace is significant in Markdown (two spaces = a hard line
|
|
15
|
+
# break), so do not strip it there.
|
|
16
|
+
[*.md]
|
|
17
|
+
trim_trailing_whitespace = false
|
|
18
|
+
|
|
19
|
+
# package.json is formatted with a 4-space tab width (see the prettier
|
|
20
|
+
# override in package.json), so match that here.
|
|
21
|
+
[package.json]
|
|
22
|
+
indent_size = 4
|
|
@@ -90,7 +90,11 @@ ENV/
|
|
|
90
90
|
.venv/
|
|
91
91
|
.env/
|
|
92
92
|
venv*/
|
|
93
|
-
.vscode
|
|
93
|
+
.vscode/*
|
|
94
|
+
# Share Prettier-on-save settings and extension recommendations; keep all
|
|
95
|
+
# other (per-user) VS Code files ignored.
|
|
96
|
+
!.vscode/settings.json
|
|
97
|
+
!.vscode/extensions.json
|
|
94
98
|
# celery beat schedule file
|
|
95
99
|
celerybeat-schedule
|
|
96
100
|
|
|
@@ -142,3 +146,8 @@ ui-tests/.tsbuild/
|
|
|
142
146
|
_site/
|
|
143
147
|
Gemfile.lock
|
|
144
148
|
|
|
149
|
+
|
|
150
|
+
# Benchmark results (may contain cost data and environment details)
|
|
151
|
+
benchmarks/claude_perf/results.json
|
|
152
|
+
benchmarks/claude_perf/__pycache__/
|
|
153
|
+
benchmarks/claude_perf/screenshots/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
[ "$HUSKY" = "2" ] && set -x
|
|
3
|
+
n=$(basename "$0")
|
|
4
|
+
s=$(dirname "$(dirname "$0")")/$n
|
|
5
|
+
|
|
6
|
+
[ ! -f "$s" ] && exit 0
|
|
7
|
+
|
|
8
|
+
if [ -f "$HOME/.huskyrc" ]; then
|
|
9
|
+
echo "husky - '~/.huskyrc' is DEPRECATED, please move your code to ~/.config/husky/init.sh"
|
|
10
|
+
fi
|
|
11
|
+
i="${XDG_CONFIG_HOME:-$HOME/.config}/husky/init.sh"
|
|
12
|
+
[ -f "$i" ] && . "$i"
|
|
13
|
+
|
|
14
|
+
[ "${HUSKY-}" = "0" ] && exit 0
|
|
15
|
+
|
|
16
|
+
export PATH="node_modules/.bin:$PATH"
|
|
17
|
+
sh -e "$s" "$@"
|
|
18
|
+
c=$?
|
|
19
|
+
|
|
20
|
+
[ $c != 0 ] && echo "husky - $n script failed (code $c)"
|
|
21
|
+
[ $c = 127 ] && echo "husky - command not found in PATH=$PATH"
|
|
22
|
+
exit $c
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
lint-staged
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"[markdown]": {
|
|
3
|
+
"editor.formatOnSave": true,
|
|
4
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
5
|
+
},
|
|
6
|
+
"[json]": {
|
|
7
|
+
"editor.formatOnSave": true,
|
|
8
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
9
|
+
},
|
|
10
|
+
"[jsonc]": {
|
|
11
|
+
"editor.formatOnSave": true,
|
|
12
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
13
|
+
},
|
|
14
|
+
"[css]": {
|
|
15
|
+
"editor.formatOnSave": true,
|
|
16
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
17
|
+
},
|
|
18
|
+
"[javascript]": {
|
|
19
|
+
"editor.formatOnSave": true,
|
|
20
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
21
|
+
},
|
|
22
|
+
"[javascriptreact]": {
|
|
23
|
+
"editor.formatOnSave": true,
|
|
24
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
25
|
+
},
|
|
26
|
+
"[typescript]": {
|
|
27
|
+
"editor.formatOnSave": true,
|
|
28
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
29
|
+
},
|
|
30
|
+
"[typescriptreact]": {
|
|
31
|
+
"editor.formatOnSave": true,
|
|
32
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -10,6 +10,50 @@ For each release we list user-facing changes grouped as **Added**, **Changed**,
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [5.1.0] - UNRELEASED
|
|
14
|
+
|
|
15
|
+
5.1.0 builds on 5.0.x with a focus on Claude-mode agent visibility. Tool calls the agent runs now render as persistent status cards with inline diffs and collapsible grouping, the generating indicator can cycle custom verbs, and cancelling a turn tears down the whole process tree the agent spawned instead of leaking it. It also adds two opt-in security guardrails (an MCP stdio-command allowlist and a default-token-password check on shared filesystems) and an always-visible mode for chat feedback. No traitlet, env-var, REST route, or on-disk-format renames or removals; every new admin surface is opt-in and listed below.
|
|
16
|
+
|
|
17
|
+
### Upgrade note
|
|
18
|
+
|
|
19
|
+
If you installed NBI before the 5.0 npm-scope rename (from `@notebook-intelligence/notebook-intelligence` to `@plmbr/notebook-intelligence`) and now see **two Notebook Intelligence icons** in the sidebar, an old labextension is lingering alongside the new one and JupyterLab is loading both. Run `jupyter labextension list`; if both scopes show as enabled, remove the stale `@notebook-intelligence` labextension directory. See [Two Notebook Intelligence icons in the sidebar](docs/troubleshooting.md#two-notebook-intelligence-icons-in-the-sidebar) (#367).
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **Claude agent tool calls render as persistent status cards** (#358). Each tool the agent runs in Claude mode appears as its own card showing a kind icon (read / edit / execute / other), a humanized label, and a live status (in progress, completed, failed, cancelled) that stays on screen after the turn ends instead of scrolling away as transient progress text. Built-in and `mcp__<server>__<tool>` names map to friendly labels, with a sentence-case fallback for unknown tools.
|
|
24
|
+
- **Inline diffs, collapsible grouping, and unified tool maps for tool-call cards** (#360). Edit-style tools (`Edit`, `MultiEdit`, `Write`, and their MCP-wrapped variants) show an inline add/remove diff on the card, capped and truncation-marked for large changes. A run of consecutive tool calls collapses into a single expandable group so a tool-heavy turn reads as one unit rather than a wall of rows; large settled groups start collapsed, live ones stay expanded. The kind/label lookups are unified into one map shared by the humanizer and the categorizer.
|
|
25
|
+
- **Custom Claude spinner verbs** (#356). When Claude mode is active, NBI reads `spinnerVerbs.verbs` from `~/.claude/settings.json` and cycles them in the generating label (Fisher-Yates shuffle, 4-7s per verb, no immediate repeats) instead of a static "Generating". The current verb is mirrored into a hidden `aria-live` region so screen readers announce verb changes without re-reading every elapsed-seconds tick.
|
|
26
|
+
- **Always-visible chat feedback** (#354). New `enable_chat_feedback_always_visible` traitlet (default `False`, requires `enable_chat_feedback = True`) renders the thumbs up/down buttons at full opacity on every assistant reply instead of revealing them on hover, and drops the post-`StreamEnd` gate so they appear with the reply. The thumbs tooltips are reworded to "Good response" / "Bad response" (screen readers announce "Rate response as good" / "Rate response as bad").
|
|
27
|
+
- **Admin allowlist for stdio MCP server commands** (#298). New `mcp_stdio_command_allowlist` traitlet and `NBI_MCP_STDIO_COMMAND_ALLOWLIST` env var (CSV, appended to the traitlet at startup). When non-empty, every stdio MCP server (added via Claude `mcp add` or loaded from `mcp.json`) must match at least one `re.search` regex or the admin gate rejects it; the empty default means no enforcement, so per-user deployments are unchanged. See [Restricting MCP stdio commands](docs/admin-guide.md#restricting-mcp-stdio-commands).
|
|
28
|
+
- **Default-token-password guardrails on shared filesystems** (#302). The GitHub Copilot token storage path now logs a per-process warning the first time it reads or writes the stored token while the public default `NBI_GH_ACCESS_TOKEN_PASSWORD` is in use, escalated when `~/.jupyter/nbi/` is group- or other-accessible. Setting `NBI_REFUSE_DEFAULT_TOKEN_PASSWORD_ON_SHARED_FS=1` upgrades that to a hard refusal of the write when both conditions hold; `NBI_ALLOW_DEFAULT_TOKEN_PASSWORD=1` opts back out per pod. The shared-directory check is POSIX-only and the refusal is opt-in, so single-user deployments are unaffected.
|
|
29
|
+
- **Claude Code vs NBI chat performance benchmark suite** (#350). A standalone suite under `benchmarks/claude_perf/` compares response times between the `claude -p` terminal CLI and NBI's chat WebSocket path (time to first token, wall time, tokens, cost), with a runner that interleaves the two paths and separates cold from warm runs. Developer tooling; not shipped in the extension.
|
|
30
|
+
- **Opt-in Prettier pre-commit hook and editor format-on-save** (#355). A husky + lint-staged hook formats staged files on commit, alongside EditorConfig and VS Code format-on-save settings. Developer tooling.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- **Notebook-agent prompts and tool responses** (#351). Notebook editing/execution prompts now encourage incremental analysis and intermediate validation rather than generating a whole notebook in one pass; `add-code-cell` and `add-markdown-cell` return the inserted `cellIndex` for traceability; and `read_file` caps its output with UTF-8-safe truncation so large reads stay within a budget.
|
|
35
|
+
- **Expandable parameter/detail boxes use a flat fill** instead of the inner-glow effect (#361), for a cleaner read in both light and dark themes.
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- **Cancelling a Claude turn tears down the whole process tree** the agent spawned (#357). A cancel previously killed only the direct `claude` CLI child, leaking reparented shells, MCP servers, and dev servers that accumulated across cancels and restarts; NBI now reaps the agent's descendants, gracefully then forcefully, without signalling the Jupyter server's own process group.
|
|
40
|
+
- **Claude session-resume commands are shell-quoted** (#349). Resume launches route through the shared command builder and quote the transcript-derived session id, so malicious session metadata cannot break out of `claude --resume` into shell execution.
|
|
41
|
+
- **Forged upload-context paths are rejected** (#348). WebSocket upload attachments must resolve under the server upload root before an image read or Claude file mention uses the supplied path, closing the forged `isUpload` path that could point chat context at arbitrary server-readable files outside the workspace.
|
|
42
|
+
- **Tool-call diffs are readable in dark theme and the tool-call group no longer flickers** (#360, #364). Diff add/remove lines use semi-transparent tints over the card so the theme's own text color stays legible in both themes (the `--jp-*-color3` fills were light pastels in both); and the streaming response keeps a stable message identity, so the tool-call group no longer expands and collapses on its own as calls arrive.
|
|
43
|
+
|
|
44
|
+
## [5.0.1] - 2026-05-24
|
|
45
|
+
|
|
46
|
+
A patch release: one provider-compatibility fix, one chat-rendering fix, and the npm package-scope rename. No traitlet, env-var, REST route, or on-disk-format changes; no migration steps beyond the 5.0.0 note.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- **GitHub Copilot Codex chat models route through the `/responses` endpoint** (#341). Codex-family models (e.g. `gpt-5.3-codex`) are served only by Copilot's OpenAI Responses API mirror and return HTTP 400 on the standard `/chat/completions` path, so selecting one in the chat-model dropdown previously failed. NBI now picks the endpoint per model from the `/models` catalog's `supported_endpoints` field (with a `codex` substring fallback for offline sessions), translates the request and streaming events to the Responses shape, and surfaces `response.failed` / `response.error` / `response.incomplete` / `error` events instead of an empty turn. No new settings; the dispatch is internal to the GitHub Copilot provider.
|
|
51
|
+
- **npm package scope renamed to `@plmbr/notebook-intelligence`** (#342), following the GitHub org rename from `notebook-intelligence` to `plmbr`. The labextension is now listed as `@plmbr/notebook-intelligence` in `jupyter labextension list`; the pip package name (`notebook-intelligence`) is unchanged, so `pip install notebook-intelligence` still works.
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- **AI-generated links in the chat sidebar open in a new tab instead of replacing the JupyterLab UI** (#347). Markdown links emitted by the model previously navigated the top-level document and unloaded the whole Lab session on click. External links (`http` / `https` / `mailto`) now open with `target="_blank" rel="noopener noreferrer"`; workspace-relative paths open the referenced file through JupyterLab's document manager; fragment-only links render as inert text; and disallowed schemes (`javascript:`, traversal-escaping paths, dangerous codepoints) are blocked.
|
|
56
|
+
|
|
13
57
|
## [5.0.0] - 2026-05-22
|
|
14
58
|
|
|
15
59
|
5.0.0 is a major release built on top of 4.8.0, gathering a large surface of new admin policies, accessibility work across the chat sidebar / popovers / settings tabs, several security hardening passes, and three new agent-aware UI surfaces. Most existing configuration continues to work; the version bump reflects the breadth of new admin-policy / env-var surface that operators should review, plus the dependency swap from `fastmcp` to the official `mcp` SDK.
|
|
@@ -330,7 +374,8 @@ A multi-PR accessibility pass landed across most NBI surfaces. Together these ma
|
|
|
330
374
|
- Settings UI restructured around Claude vs default mode.
|
|
331
375
|
- WebSocket connection reliability improvements.
|
|
332
376
|
|
|
333
|
-
[unreleased]: https://github.com/plmbr/notebook-intelligence/compare/v5.0.
|
|
377
|
+
[unreleased]: https://github.com/plmbr/notebook-intelligence/compare/v5.0.1...HEAD
|
|
378
|
+
[5.0.1]: https://github.com/plmbr/notebook-intelligence/compare/v5.0.0...v5.0.1
|
|
334
379
|
[5.0.0]: https://github.com/plmbr/notebook-intelligence/compare/v4.8.0...v5.0.0
|
|
335
380
|
[4.8.0]: https://github.com/plmbr/notebook-intelligence/compare/v4.7.0...v4.8.0
|
|
336
381
|
[4.7.0]: https://github.com/plmbr/notebook-intelligence/compare/v4.6.0...v4.7.0
|
|
@@ -32,7 +32,7 @@ NBI has two halves:
|
|
|
32
32
|
- `notebook_intelligence/ai_service_manager.py` — composes LLM providers, MCP, skills, and rules into the request pipeline.
|
|
33
33
|
- `notebook_intelligence/llm_providers/` — provider adapters (GitHub Copilot, OpenAI-compatible, LiteLLM-compatible, Ollama).
|
|
34
34
|
- `notebook_intelligence/claude.py` + `notebook_intelligence/claude_sessions.py` — Claude Code integration via [`claude-agent-sdk`](https://pypi.org/project/claude-agent-sdk/).
|
|
35
|
-
- `notebook_intelligence/mcp_manager.py
|
|
35
|
+
- `notebook_intelligence/mcp_manager.py`: MCP server management via the official [`mcp`](https://pypi.org/project/mcp/) SDK (replaced `fastmcp` in 5.0.0).
|
|
36
36
|
- `notebook_intelligence/skill_manager.py`, `skill_github_import.py`, `skill_manifest.py`, `skill_reconciler.py`, `skillset.py` — Claude Skills storage, GitHub import, and managed-manifest reconciliation.
|
|
37
37
|
- `notebook_intelligence/rule_manager.py`, `rule_injector.py`, `ruleset.py` — ruleset discovery and prompt injection.
|
|
38
38
|
- `notebook_intelligence/built_in_toolsets.py` — built-in tool implementations (`nbi-notebook-edit`, `nbi-command-execute`, etc.).
|
|
@@ -176,6 +176,15 @@ jlpm lint # check and auto-fix prettier, eslint, and stylelint
|
|
|
176
176
|
|
|
177
177
|
CI runs `lint:check`. Identifiers prefixed with `_` are treated as intentionally unused and excluded from the unused-vars rule.
|
|
178
178
|
|
|
179
|
+
### Automatic formatting
|
|
180
|
+
|
|
181
|
+
Two optional layers catch formatting drift before it reaches CI, so a common lint failure (an unformatted `.md`, `.ts`, or `.css` file) never makes it into a commit:
|
|
182
|
+
|
|
183
|
+
- **Pre-commit hook.** `jlpm install` registers a [Husky](https://typicode.github.io/husky/) hook (via a `postinstall` script) that runs `prettier --write` on staged files through [lint-staged](https://github.com/lint-staged/lint-staged). Staged files are formatted and re-staged automatically before the commit completes. Husky no-ops when there is no Git checkout (for example during `pip install` builds from an sdist) and when `HUSKY=0` is set, so it never affects packaging. To skip it for a single commit, use `git commit --no-verify`; to opt out entirely, run `HUSKY=0 jlpm install`.
|
|
184
|
+
- **Editor format-on-save.** `.editorconfig` and `.vscode/` settings format files with Prettier on save. Install the recommended VS Code extensions (you will be prompted, or see `.vscode/extensions.json`) to enable it.
|
|
185
|
+
|
|
186
|
+
Both layers only run Prettier, which is safe to apply automatically; ESLint and Stylelint rule violations are still left for you and CI to surface. Neither layer changes what CI enforces; both just move the formatting fix earlier. `jlpm lint` remains the manual catch-all.
|
|
187
|
+
|
|
179
188
|
If `jlpm install` produces unexpected lockfile changes, your local Yarn version probably differs from the one bundled with JupyterLab. `jlpm` ships with JupyterLab — use it directly instead of a system-wide `yarn`.
|
|
180
189
|
|
|
181
190
|
## Packaging
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: notebook_intelligence
|
|
3
|
-
Version: 5.0
|
|
3
|
+
Version: 5.1.0
|
|
4
4
|
Summary: AI coding assistant for JupyterLab
|
|
5
5
|
Project-URL: Homepage, https://github.com/plmbr/notebook-intelligence
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/plmbr/notebook-intelligence/issues
|
|
@@ -704,6 +704,7 @@ Requires-Dist: mcp>=1.27.0
|
|
|
704
704
|
Requires-Dist: mistune>=3.2.1
|
|
705
705
|
Requires-Dist: ollama
|
|
706
706
|
Requires-Dist: openai
|
|
707
|
+
Requires-Dist: psutil>=5.7
|
|
707
708
|
Requires-Dist: python-multipart>=0.0.27
|
|
708
709
|
Requires-Dist: sseclient-py
|
|
709
710
|
Requires-Dist: tiktoken
|
|
@@ -811,7 +812,7 @@ If the Claude Code CLI is on `PATH`, NBI launches it automatically. To override
|
|
|
811
812
|
|
|
812
813
|
When Claude mode is on, the chat sidebar shows a history icon next to the gear. Click it to list the Claude Code sessions recorded for the current working directory (the same transcripts the Claude Code CLI stores under `~/.claude/projects/`). Selecting a session reconnects via `resume`, so the next message you send continues that transcript with full prior context. A **New chat session** button next to the gear restarts the SDK client without typing `/clear`.
|
|
813
814
|
|
|
814
|
-
Long Claude turns surface an elapsed-time counter
|
|
815
|
+
Long Claude turns surface an elapsed-time counter and a heartbeat-driven pulse with a "may be slow" copy flip after 30 seconds. Each tool the agent runs shows up as a persistent status card with a kind icon and a live in-progress / done / failed state; edits carry an inline diff, and a run of consecutive calls collapses into one expandable group, so the sidebar reflects what the agent is doing rather than appearing stuck.
|
|
815
816
|
|
|
816
817
|
In Claude mode, workspace files attached as chat context arrive as `@`-mention pointers rather than inlined file contents. Claude's Read tool fetches them on demand, which means images, large files, and notebooks (cell-aware) now work where the older content-injection path silently truncated or skipped them.
|
|
817
818
|
|
|
@@ -1100,6 +1101,12 @@ jupyter lab --NotebookIntelligence.enable_chat_feedback=true
|
|
|
1100
1101
|
|
|
1101
1102
|
The feedback fires an in-process `telemetry` event. Nothing leaves the process by default — see the [admin guide](docs/admin-guide.md#chat-feedback-event-hook) for how to wire it into your observability stack.
|
|
1102
1103
|
|
|
1104
|
+
The thumbs buttons reveal on hover by default. To keep them always visible, enable:
|
|
1105
|
+
|
|
1106
|
+
```python
|
|
1107
|
+
c.NotebookIntelligence.enable_chat_feedback_always_visible = True
|
|
1108
|
+
```
|
|
1109
|
+
|
|
1103
1110
|
<img src="media/chat-feedback.png" alt="Chat feedback" width=500 />
|
|
1104
1111
|
|
|
1105
1112
|
## Documentation
|
|
@@ -58,7 +58,7 @@ For air-gapped or egress-restricted environments, see [`docs/admin-guide.md`](do
|
|
|
58
58
|
|
|
59
59
|
> Treat `~/.jupyter/nbi/config.json` and `~/.jupyter/nbi/user-data.json` as secrets. They contain your API keys and (encrypted) GitHub token. Do not commit them to git, share them, or sync them across users. If a key leaks, rotate it at the provider immediately.
|
|
60
60
|
|
|
61
|
-
The encrypted GitHub token uses a default password (`nbi-access-token-password`) unless you set `NBI_GH_ACCESS_TOKEN_PASSWORD`. The default is **shared across installs** and provides obfuscation, not real protection. Set a custom password before enabling "remember login" on any shared or multi-tenant system.
|
|
61
|
+
The encrypted GitHub token uses a default password (`nbi-access-token-password`) unless you set `NBI_GH_ACCESS_TOKEN_PASSWORD`. The default is **shared across installs** and provides obfuscation, not real protection. Set a custom password before enabling "remember login" on any shared or multi-tenant system. NBI logs a per-process WARNING when the default is in use and escalates the message when `~/.jupyter/nbi/` is group/other-accessible. Operators on shared filesystems can set `NBI_REFUSE_DEFAULT_TOKEN_PASSWORD_ON_SHARED_FS=1` to refuse the write entirely until a per-user password is configured, with `NBI_ALLOW_DEFAULT_TOKEN_PASSWORD=1` available as an explicit per-pod opt-out during a rollout.
|
|
62
62
|
|
|
63
63
|
## Telemetry
|
|
64
64
|
|
|
@@ -94,7 +94,7 @@ If the Claude Code CLI is on `PATH`, NBI launches it automatically. To override
|
|
|
94
94
|
|
|
95
95
|
When Claude mode is on, the chat sidebar shows a history icon next to the gear. Click it to list the Claude Code sessions recorded for the current working directory (the same transcripts the Claude Code CLI stores under `~/.claude/projects/`). Selecting a session reconnects via `resume`, so the next message you send continues that transcript with full prior context. A **New chat session** button next to the gear restarts the SDK client without typing `/clear`.
|
|
96
96
|
|
|
97
|
-
Long Claude turns surface an elapsed-time counter
|
|
97
|
+
Long Claude turns surface an elapsed-time counter and a heartbeat-driven pulse with a "may be slow" copy flip after 30 seconds. Each tool the agent runs shows up as a persistent status card with a kind icon and a live in-progress / done / failed state; edits carry an inline diff, and a run of consecutive calls collapses into one expandable group, so the sidebar reflects what the agent is doing rather than appearing stuck.
|
|
98
98
|
|
|
99
99
|
In Claude mode, workspace files attached as chat context arrive as `@`-mention pointers rather than inlined file contents. Claude's Read tool fetches them on demand, which means images, large files, and notebooks (cell-aware) now work where the older content-injection path silently truncated or skipped them.
|
|
100
100
|
|
|
@@ -383,6 +383,12 @@ jupyter lab --NotebookIntelligence.enable_chat_feedback=true
|
|
|
383
383
|
|
|
384
384
|
The feedback fires an in-process `telemetry` event. Nothing leaves the process by default — see the [admin guide](docs/admin-guide.md#chat-feedback-event-hook) for how to wire it into your observability stack.
|
|
385
385
|
|
|
386
|
+
The thumbs buttons reveal on hover by default. To keep them always visible, enable:
|
|
387
|
+
|
|
388
|
+
```python
|
|
389
|
+
c.NotebookIntelligence.enable_chat_feedback_always_visible = True
|
|
390
|
+
```
|
|
391
|
+
|
|
386
392
|
<img src="media/chat-feedback.png" alt="Chat feedback" width=500 />
|
|
387
393
|
|
|
388
394
|
## Documentation
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Claude Code Performance Benchmark
|
|
2
|
+
|
|
3
|
+
Compare Claude Code response times between the terminal CLI and NBI's chat sidebar.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd benchmarks/claude_perf
|
|
9
|
+
|
|
10
|
+
# Smoke test (terminal only, 2 iterations, one prompt)
|
|
11
|
+
python bench_runner.py --iterations 2 --prompts short --terminal-only
|
|
12
|
+
|
|
13
|
+
# Full terminal benchmark (25 iterations, all prompts)
|
|
14
|
+
python bench_runner.py --iterations 25 --terminal-only
|
|
15
|
+
|
|
16
|
+
# Full comparison (requires JupyterLab running on :8889 with Claude mode on)
|
|
17
|
+
python bench_runner.py --iterations 25
|
|
18
|
+
|
|
19
|
+
# Non-interleaved (all terminal first, then all NBI)
|
|
20
|
+
python bench_runner.py --iterations 25 --no-interleave
|
|
21
|
+
|
|
22
|
+
# View results
|
|
23
|
+
python report.py
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## What it measures
|
|
27
|
+
|
|
28
|
+
| Metric | Terminal | NBI Chat |
|
|
29
|
+
| ----------------- | ---------------------------------- | ----------------------------------------------- |
|
|
30
|
+
| TTFT (ms) | From Claude CLI's `result.ttft_ms` | From WebSocket send to first `nbiContent` chunk |
|
|
31
|
+
| Wall time (ms) | subprocess spawn to exit | WebSocket send to `stream-end` |
|
|
32
|
+
| CLI duration (ms) | `result.duration_ms` | n/a |
|
|
33
|
+
| API duration (ms) | `result.duration_api_ms` | n/a |
|
|
34
|
+
| Output tokens | From `result.usage` | n/a |
|
|
35
|
+
| Output chars | From `result.result` text length | From streamed markdown chunks |
|
|
36
|
+
|
|
37
|
+
## Methodology notes
|
|
38
|
+
|
|
39
|
+
This benchmark measures **end-to-end user-perceived latency** for each surface, not isolated NBI overhead. Several structural asymmetries should be kept in mind when interpreting results:
|
|
40
|
+
|
|
41
|
+
**Different process models.** The terminal path spawns a fresh `claude -p` subprocess per run (pays Node.js startup, config loading, MCP server discovery each time). The NBI path hits an already-running JupyterLab server where the Agent SDK client is warm. This means the terminal "cold" cost is higher than NBI's, but for a different reason than NBI overhead.
|
|
42
|
+
|
|
43
|
+
**Different system prompts.** The `claude -p` CLI loads `~/.claude/CLAUDE.md`, project CLAUDE.md, skills, and MCP tool schemas into its system prompt. NBI builds a shorter JupyterLab-specific prompt. Different input token counts affect TTFT via prompt-cache behavior: each path warms its own cache key, and the first run in each block pays `cache_creation_input_tokens` cost.
|
|
44
|
+
|
|
45
|
+
**Prompt cache confound.** Run 0 ("cold") in each path is tagged separately and excluded from the comparison table's warm-only medians. The comparison table reflects steady-state performance after caches are populated.
|
|
46
|
+
|
|
47
|
+
**API latency dominates.** Claude API TTFT commonly spans 800-3000ms depending on load and cache state. NBI's local overhead (WebSocket parsing, thread dispatch, Agent SDK query: ~200-500ms) is a fraction of one standard deviation of API latency. With 25 samples, detecting a real 300ms difference on top of 2-5s API calls requires looking at the interleaved paired medians, not individual run comparisons.
|
|
48
|
+
|
|
49
|
+
**Interleaving.** By default, terminal and NBI runs are interleaved (terminal-NBI-terminal-NBI) to cancel out API load drift over the run. Use `--no-interleave` for block-sequential if needed.
|
|
50
|
+
|
|
51
|
+
## Prerequisites
|
|
52
|
+
|
|
53
|
+
- `claude` CLI on PATH (Claude Code 2.x)
|
|
54
|
+
- For NBI benchmarks: JupyterLab running with NBI installed, Claude mode enabled, no auth token (or pass `--nbi-token`)
|
|
55
|
+
- `pip install websockets` (for the WebSocket benchmark)
|
|
56
|
+
|
|
57
|
+
## Files
|
|
58
|
+
|
|
59
|
+
- `bench_terminal.py` - runs one prompt through `claude -p --output-format stream-json --verbose`
|
|
60
|
+
- `bench_nbi_ws.py` - connects to NBI's WebSocket and sends one chat request
|
|
61
|
+
- `bench_runner.py` - orchestrator (iterations, prompt bank, cold/warm, interleaving, summary table)
|
|
62
|
+
- `report.py` - reads `results.json` and prints formatted comparison with histograms
|
|
63
|
+
- `prompts.py` - the prompt bank (short / medium / code / long)
|
|
64
|
+
- `stats.py` - shared `summarize()` helper
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""Benchmark Claude Code through NBI's WebSocket chat endpoint.
|
|
2
|
+
|
|
3
|
+
Connects to `ws://host:port/notebook-intelligence/copilot`, sends a
|
|
4
|
+
chat-request message, and measures timing from the outside:
|
|
5
|
+
|
|
6
|
+
- `ttft_ms`: time from message-send to first content chunk
|
|
7
|
+
- `wall_ms`: time from message-send to stream-end signal
|
|
8
|
+
- `output_chars`: total characters in the streamed assistant reply
|
|
9
|
+
|
|
10
|
+
JupyterLab must be running with NBI installed and Claude mode enabled.
|
|
11
|
+
The server token (if any) must be empty or passed via `--token`.
|
|
12
|
+
|
|
13
|
+
Protocol notes (from extension.py):
|
|
14
|
+
- Streaming chunks arrive as JSON with `choices[0].delta.nbiContent`
|
|
15
|
+
where `nbiContent.type` is "markdown", "markdown_part", etc.
|
|
16
|
+
- The finish signal is `{"type": "stream-end", ...}`.
|
|
17
|
+
- Heartbeats arrive as `{"type": "claude-code-heartbeat", ...}`.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import asyncio
|
|
21
|
+
import json
|
|
22
|
+
import time
|
|
23
|
+
import uuid
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
import websockets
|
|
27
|
+
except ImportError:
|
|
28
|
+
websockets = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
async def run_once_async(
|
|
32
|
+
prompt: str,
|
|
33
|
+
*,
|
|
34
|
+
host: str = "localhost",
|
|
35
|
+
port: int = 8889,
|
|
36
|
+
token: str = "",
|
|
37
|
+
) -> dict:
|
|
38
|
+
if websockets is None:
|
|
39
|
+
return {"error": "websockets package not installed (pip install websockets)"}
|
|
40
|
+
|
|
41
|
+
url = f"ws://{host}:{port}/notebook-intelligence/copilot"
|
|
42
|
+
if token:
|
|
43
|
+
url += f"?token={token}"
|
|
44
|
+
|
|
45
|
+
chat_id = str(uuid.uuid4())
|
|
46
|
+
message_id = str(uuid.uuid4())
|
|
47
|
+
|
|
48
|
+
request = json.dumps({
|
|
49
|
+
"id": message_id,
|
|
50
|
+
"type": "chat-request",
|
|
51
|
+
"data": {
|
|
52
|
+
"chatId": chat_id,
|
|
53
|
+
"prompt": prompt,
|
|
54
|
+
"language": "python",
|
|
55
|
+
"filename": "benchmark.py",
|
|
56
|
+
"chatMode": "ask",
|
|
57
|
+
"toolSelections": {},
|
|
58
|
+
"additionalContext": [],
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
first_content_time = None
|
|
63
|
+
total_chars = 0
|
|
64
|
+
finished = False
|
|
65
|
+
error_msg = None
|
|
66
|
+
|
|
67
|
+
wall_start = time.perf_counter()
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
async with websockets.connect(url, close_timeout=5, max_size=10 * 1024 * 1024) as ws:
|
|
71
|
+
await ws.send(request)
|
|
72
|
+
|
|
73
|
+
while not finished:
|
|
74
|
+
try:
|
|
75
|
+
raw = await asyncio.wait_for(ws.recv(), timeout=120)
|
|
76
|
+
except asyncio.TimeoutError:
|
|
77
|
+
error_msg = "timed out waiting for response (120s)"
|
|
78
|
+
break
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
msg = json.loads(raw)
|
|
82
|
+
except json.JSONDecodeError:
|
|
83
|
+
continue
|
|
84
|
+
|
|
85
|
+
msg_type = msg.get("type")
|
|
86
|
+
|
|
87
|
+
# NBI stream-end signal
|
|
88
|
+
if msg_type == "stream-end":
|
|
89
|
+
finished = True
|
|
90
|
+
continue
|
|
91
|
+
|
|
92
|
+
# Heartbeat (ignore for timing, but proves the connection is alive)
|
|
93
|
+
if msg_type == "claude-code-heartbeat":
|
|
94
|
+
continue
|
|
95
|
+
|
|
96
|
+
# Streaming content: wrapped as
|
|
97
|
+
# {"type": "stream-message", "data": {"choices": [...]}}
|
|
98
|
+
data = msg.get("data") or {}
|
|
99
|
+
choices = data.get("choices") if isinstance(data, dict) else None
|
|
100
|
+
if isinstance(choices, list) and choices:
|
|
101
|
+
delta = choices[0].get("delta", {})
|
|
102
|
+
nbi = delta.get("nbiContent", {})
|
|
103
|
+
nbi_type = nbi.get("type")
|
|
104
|
+
|
|
105
|
+
if nbi_type in ("markdown", "markdown-part"):
|
|
106
|
+
content = nbi.get("content", "")
|
|
107
|
+
if content and first_content_time is None:
|
|
108
|
+
first_content_time = time.perf_counter()
|
|
109
|
+
total_chars += len(content)
|
|
110
|
+
|
|
111
|
+
except Exception as e:
|
|
112
|
+
error_msg = str(e)
|
|
113
|
+
|
|
114
|
+
wall_end = time.perf_counter()
|
|
115
|
+
wall_ms = round((wall_end - wall_start) * 1000, 1)
|
|
116
|
+
|
|
117
|
+
if error_msg:
|
|
118
|
+
return {"error": error_msg, "wall_ms": wall_ms}
|
|
119
|
+
|
|
120
|
+
ttft_ms = (
|
|
121
|
+
round((first_content_time - wall_start) * 1000, 1)
|
|
122
|
+
if first_content_time
|
|
123
|
+
else None
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
"ttft_ms": ttft_ms,
|
|
128
|
+
"wall_ms": wall_ms,
|
|
129
|
+
"output_chars": total_chars,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def run_once(
|
|
134
|
+
prompt: str,
|
|
135
|
+
*,
|
|
136
|
+
host: str = "localhost",
|
|
137
|
+
port: int = 8889,
|
|
138
|
+
token: str = "",
|
|
139
|
+
) -> dict:
|
|
140
|
+
return asyncio.run(
|
|
141
|
+
run_once_async(prompt, host=host, port=port, token=token)
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
import pprint
|
|
147
|
+
result = run_once("What is 2+2?")
|
|
148
|
+
pprint.pprint(result)
|