notebook-intelligence 5.0.0__tar.gz → 5.0.1__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.0.0 → notebook_intelligence-5.0.1}/PKG-INFO +6 -6
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/README.md +5 -5
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/_version.py +1 -1
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/github_copilot.py +353 -1
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/package.json +2 -2
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/schemas/@plmbr/notebook-intelligence/package.json.orig +1 -1
- notebook_intelligence-5.0.1/notebook_intelligence/labextension/static/703.b2a16c3edc281d79d13a.js +1 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/editor.worker.js +2 -2
- notebook_intelligence-5.0.1/notebook_intelligence/labextension/static/remoteEntry.e77a2554241f4d36341c.js +1 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/llm_providers/github_copilot_llm_provider.py +2 -2
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/package.json +1 -1
- notebook_intelligence-5.0.1/tests/test_github_copilot_llm_provider.py +651 -0
- notebook_intelligence-5.0.1/tests/ts/markdown-renderer.test.tsx +247 -0
- notebook_intelligence-5.0.1/tests/ts/safe-anchor.test.tsx +96 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/utils.test.ts +30 -0
- notebook_intelligence-5.0.0/notebook_intelligence/labextension/static/784.e320c845743830167ef6.js +0 -1
- notebook_intelligence-5.0.0/notebook_intelligence/labextension/static/remoteEntry.4708b983f8e8c8f2abe1.js +0 -1
- notebook_intelligence-5.0.0/tests/test_github_copilot_llm_provider.py +0 -166
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/.copier-answers.yml +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/.gitignore +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/.prettierignore +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/.yarnrc.yml +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/CHANGELOG.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/CONTRIBUTING.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/LICENSE +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/PRIVACY.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/RELEASE.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/SECURITY.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/docs/admin-guide.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/docs/admin-tour-config.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/docs/rulesets.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/docs/skills.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/docs/troubleshooting.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/install.json +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/jest.config.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/jupyter-config/server-config/notebook_intelligence.json +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/__init__.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/_claude_cli.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/ai_service_manager.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/api.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/base_chat_participant.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/built_in_toolsets.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/cell_output.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/claude.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/claude_mcp_manager.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/claude_sessions.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/config.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/context_factory.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/extension.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/feature_flags.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/github_copilot_chat_participant.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/schemas/@plmbr/notebook-intelligence/plugin.json +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/196.da0c2020639344d5c419.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/1b55f12eca93ba6743e7.ttf +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/327.47473c656f6c27efa1dc.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/327.47473c656f6c27efa1dc.js.LICENSE.txt +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/537.02c6edab4e3a352bb107.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/631.f00d05d8305a78ec8301.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/671.1b1a53f5f75bff82950b.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/694.2ebfa9714301d9260bf0.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/728.cae98e1655349e508971.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/745.f63673e66e02301096f4.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/745.f63673e66e02301096f4.js.LICENSE.txt +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/977.b917f705175326af0e5d.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/be02dcbf2787b0b29ec8.module.wasm +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/e589c9ba04e3e5a90081.module.wasm +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/editor.worker.js.LICENSE.txt +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/style.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/labextension/static/third-party-licenses.json +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/llm_providers/litellm_compatible_llm_provider.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/llm_providers/ollama_llm_provider.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/llm_providers/openai_compatible_llm_provider.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/mcp_client.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/mcp_config_validation.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/mcp_manager.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/plugin_manager.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/prompts.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/rule_injector.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/rule_manager.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/ruleset.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/skill_github_import.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/skill_manager.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/skill_manifest.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/skill_reconciler.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/skillset.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/tour_config.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/util.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/pyproject.toml +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/schema/plugin.json +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/setup.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/conftest.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/fixtures/rules/01-test-global.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/fixtures/rules/02-test-security.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/fixtures/rules/03-invalid-rule.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/fixtures/rules/modes/agent/01-test-production.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/fixtures/rules/modes/ask/01-test-exploration.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/fixtures/rules/modes/inline-chat/01-test-quick.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_ai_service_manager_integration.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_api_hygiene.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_base_chat_participant_integration.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_builtin_toolset_cwd_sandbox.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_cell_output.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_cell_output_features_response.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_claude_client.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_claude_mcp_manager.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_claude_models.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_claude_sessions.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_claude_sessions_handler.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_claude_system_prompt.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_claude_tool_humanizer.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_claude_tool_path_sandbox.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_coding_agent_launchers.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_config_atomic_save.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_config_integration.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_context_factory.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_end_to_end_rule_integration.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_feature_flags.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_feedback.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_file_upload.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_github_copilot_user_data_mode.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_image_context.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_mcp_client_shim.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_mcp_config_validation.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_mcp_manager.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_models.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_openai_compatible_llm_provider.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_plugin_manager.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_policy_gate.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_redact_process_secrets.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_response_emitter.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_rule_auto_reload.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_rule_injector.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_rule_manager.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_safe_anchor_uri.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_skill_fetch_redirects.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_skill_github_import.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_skill_manager.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_skill_manifest.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_skill_reconciler.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_skills_handlers.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_tour_config.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_websocket_handler_integration.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_ws_callback_handler_leak.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/test_ws_handler_auth.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/__mocks__/jupyterlab-apputils.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/__mocks__/jupyterlab-filebrowser.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/__mocks__/svg.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/__mocks__/tiktoken.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/ask-user-question.test.tsx +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/cell-output-bundle.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/cell-output-features.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/cell-output-toolbar.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/chat-progress-feedback.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/checkbox.test.tsx +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/choose-workspace-directory.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/claude-mcp-paste.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/coding-agent-launchers.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/launcher-picker.test.tsx +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/mcp-util.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/notebook-generation.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/open-file-refresh-watcher.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/plugins-panel.test.tsx +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/setup.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/skill-wire-format.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/task-target-notebook.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/terminal-drag.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/tour-config.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/tour-events.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/tour-overlay.test.tsx +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/tour-state.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/tsconfig.json +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tests/ts/workspace-skips.test.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/tsconfig.json +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/.eslintrc.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/README.md +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/jupyter_server_test_config.py +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/package.json +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/playwright.config.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/tests/cell-output.spec.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/tests/chat-sidebar.spec.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/tests/claude-mcp-patch.spec.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/tests/extension.spec.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/tests/helpers.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/tests/launcher.spec.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/tests/notebook-toolbar.spec.ts +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/tsconfig.json +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/ui-tests/yarn.lock +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/webpack.config.js +0 -0
- {notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/yarn.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: notebook_intelligence
|
|
3
|
-
Version: 5.0.
|
|
3
|
+
Version: 5.0.1
|
|
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
|
|
@@ -876,7 +876,7 @@ NBI reloads open document tabs when their files change on disk, so edits an AI a
|
|
|
876
876
|
|
|
877
877
|
## Configuration
|
|
878
878
|
|
|
879
|
-
Configure your provider, model, and API key from NBI Settings — the gear icon in the chat panel, the `/settings` chat command, or the JupyterLab command palette. For background, see the [provider blog post](https://
|
|
879
|
+
Configure your provider, model, and API key from NBI Settings — the gear icon in the chat panel, the `/settings` chat command, or the JupyterLab command palette. For background, see the [provider blog post](https://plmbr.dev/blog/archive/support-for-any-llm-provider/).
|
|
880
880
|
|
|
881
881
|
<img src="media/provider-list.png" alt="Settings dialog" width=500 />
|
|
882
882
|
|
|
@@ -1115,10 +1115,10 @@ The feedback fires an in-process `telemetry` event. Nothing leaves the process b
|
|
|
1115
1115
|
|
|
1116
1116
|
## Further reading
|
|
1117
1117
|
|
|
1118
|
-
- [Introducing Notebook Intelligence!](https://
|
|
1119
|
-
- [Building AI Extensions for JupyterLab](https://
|
|
1120
|
-
- [Building AI Agents for JupyterLab](https://
|
|
1121
|
-
- [Notebook Intelligence now supports any LLM Provider and AI Model!](https://
|
|
1118
|
+
- [Introducing Notebook Intelligence!](https://plmbr.dev/blog/archive/introducing-notebook-intelligence/)
|
|
1119
|
+
- [Building AI Extensions for JupyterLab](https://plmbr.dev/blog/archive/building-ai-extensions-for-jupyterlab/)
|
|
1120
|
+
- [Building AI Agents for JupyterLab](https://plmbr.dev/blog/archive/building-ai-agents-for-jupyterlab/)
|
|
1121
|
+
- [Notebook Intelligence now supports any LLM Provider and AI Model!](https://plmbr.dev/blog/archive/support-for-any-llm-provider/)
|
|
1122
1122
|
|
|
1123
1123
|
## Roadmap
|
|
1124
1124
|
|
|
@@ -159,7 +159,7 @@ NBI reloads open document tabs when their files change on disk, so edits an AI a
|
|
|
159
159
|
|
|
160
160
|
## Configuration
|
|
161
161
|
|
|
162
|
-
Configure your provider, model, and API key from NBI Settings — the gear icon in the chat panel, the `/settings` chat command, or the JupyterLab command palette. For background, see the [provider blog post](https://
|
|
162
|
+
Configure your provider, model, and API key from NBI Settings — the gear icon in the chat panel, the `/settings` chat command, or the JupyterLab command palette. For background, see the [provider blog post](https://plmbr.dev/blog/archive/support-for-any-llm-provider/).
|
|
163
163
|
|
|
164
164
|
<img src="media/provider-list.png" alt="Settings dialog" width=500 />
|
|
165
165
|
|
|
@@ -398,10 +398,10 @@ The feedback fires an in-process `telemetry` event. Nothing leaves the process b
|
|
|
398
398
|
|
|
399
399
|
## Further reading
|
|
400
400
|
|
|
401
|
-
- [Introducing Notebook Intelligence!](https://
|
|
402
|
-
- [Building AI Extensions for JupyterLab](https://
|
|
403
|
-
- [Building AI Agents for JupyterLab](https://
|
|
404
|
-
- [Notebook Intelligence now supports any LLM Provider and AI Model!](https://
|
|
401
|
+
- [Introducing Notebook Intelligence!](https://plmbr.dev/blog/archive/introducing-notebook-intelligence/)
|
|
402
|
+
- [Building AI Extensions for JupyterLab](https://plmbr.dev/blog/archive/building-ai-extensions-for-jupyterlab/)
|
|
403
|
+
- [Building AI Agents for JupyterLab](https://plmbr.dev/blog/archive/building-ai-agents-for-jupyterlab/)
|
|
404
|
+
- [Notebook Intelligence now supports any LLM Provider and AI Model!](https://plmbr.dev/blog/archive/support-for-any-llm-provider/)
|
|
405
405
|
|
|
406
406
|
## Roadmap
|
|
407
407
|
|
{notebook_intelligence-5.0.0 → notebook_intelligence-5.0.1}/notebook_intelligence/github_copilot.py
RENAMED
|
@@ -59,6 +59,16 @@ github_auth = {
|
|
|
59
59
|
# stay current.
|
|
60
60
|
copilot_models_cache: list[dict] = []
|
|
61
61
|
|
|
62
|
+
# Per-model HTTP path under API_ENDPOINT. Codex-class models advertise only
|
|
63
|
+
# `/responses` (the OpenAI Responses API mirror) and 400 on `/chat/completions`;
|
|
64
|
+
# everything else stays on `/chat/completions`. Populated by
|
|
65
|
+
# `fetch_copilot_models` from each model entry's `supported_endpoints` field.
|
|
66
|
+
# Lookup falls back to `/chat/completions` for unknown ids so the hardcoded
|
|
67
|
+
# fallback model list keeps working before the first live fetch.
|
|
68
|
+
_COPILOT_CHAT_ENDPOINT = "/chat/completions"
|
|
69
|
+
_COPILOT_RESPONSES_ENDPOINT = "/responses"
|
|
70
|
+
copilot_model_endpoints: dict[str, str] = {}
|
|
71
|
+
|
|
62
72
|
# Conservative floor when the Copilot API omits limits for a model. Picked
|
|
63
73
|
# to match the smallest token cap any Copilot-served model has historically
|
|
64
74
|
# carried, so the token-budget meter (extension.py: `remaining_token_budget`)
|
|
@@ -419,6 +429,7 @@ def fetch_copilot_models() -> list[dict]:
|
|
|
419
429
|
|
|
420
430
|
raw_models = payload.get("data", []) if isinstance(payload, dict) else []
|
|
421
431
|
normalized: list[dict] = []
|
|
432
|
+
endpoints: dict[str, str] = {}
|
|
422
433
|
seen_ids: set[str] = set()
|
|
423
434
|
for entry in raw_models:
|
|
424
435
|
if not isinstance(entry, dict):
|
|
@@ -426,7 +437,15 @@ def fetch_copilot_models() -> list[dict]:
|
|
|
426
437
|
if not entry.get("model_picker_enabled"):
|
|
427
438
|
continue
|
|
428
439
|
caps = entry.get("capabilities", {}) or {}
|
|
429
|
-
|
|
440
|
+
supported = entry.get("supported_endpoints") or []
|
|
441
|
+
if not isinstance(supported, list):
|
|
442
|
+
supported = []
|
|
443
|
+
# Codex-class models advertise only `/responses` and may report a
|
|
444
|
+
# non-chat capability `type`. Accept them when the endpoint list says
|
|
445
|
+
# they're chattable, so they reach the dispatcher in `chat(...)`.
|
|
446
|
+
is_chat_type = caps.get("type") == "chat"
|
|
447
|
+
has_responses = _COPILOT_RESPONSES_ENDPOINT in supported
|
|
448
|
+
if not (is_chat_type or has_responses):
|
|
430
449
|
continue
|
|
431
450
|
model_id = entry.get("id")
|
|
432
451
|
if not isinstance(model_id, str) or not model_id or model_id in seen_ids:
|
|
@@ -445,6 +464,15 @@ def fetch_copilot_models() -> list[dict]:
|
|
|
445
464
|
context_window = _COPILOT_DEFAULT_CONTEXT_WINDOW
|
|
446
465
|
if context_window <= 0:
|
|
447
466
|
context_window = _COPILOT_DEFAULT_CONTEXT_WINDOW
|
|
467
|
+
# Prefer `/chat/completions` whenever the model advertises it; only
|
|
468
|
+
# route through `/responses` when that's the model's sole supported
|
|
469
|
+
# path. Mirrors codecompanion.nvim's Copilot adapter: dual-listing
|
|
470
|
+
# exists for forward compatibility, but established chat flows are
|
|
471
|
+
# still cheaper on the older endpoint.
|
|
472
|
+
if has_responses and _COPILOT_CHAT_ENDPOINT not in supported:
|
|
473
|
+
endpoints[model_id] = _COPILOT_RESPONSES_ENDPOINT
|
|
474
|
+
else:
|
|
475
|
+
endpoints[model_id] = _COPILOT_CHAT_ENDPOINT
|
|
448
476
|
normalized.append({
|
|
449
477
|
"id": model_id,
|
|
450
478
|
"name": str(name),
|
|
@@ -460,12 +488,33 @@ def fetch_copilot_models() -> list[dict]:
|
|
|
460
488
|
|
|
461
489
|
copilot_models_cache.clear()
|
|
462
490
|
copilot_models_cache.extend(normalized)
|
|
491
|
+
copilot_model_endpoints.clear()
|
|
492
|
+
copilot_model_endpoints.update(endpoints)
|
|
463
493
|
return list(copilot_models_cache)
|
|
464
494
|
|
|
465
495
|
|
|
466
496
|
def invalidate_copilot_models_cache() -> None:
|
|
467
497
|
"""Clear the memoized Copilot chat-model list. Mostly used by tests."""
|
|
468
498
|
copilot_models_cache.clear()
|
|
499
|
+
copilot_model_endpoints.clear()
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def _model_chat_endpoint(model_id: str) -> str:
|
|
503
|
+
"""Pick the HTTP path for a Copilot chat request.
|
|
504
|
+
|
|
505
|
+
Trusts the live catalogue first: `fetch_copilot_models` populates
|
|
506
|
+
`copilot_model_endpoints` after login from each model's
|
|
507
|
+
`supported_endpoints` field. For ids the cache doesn't know (the
|
|
508
|
+
hardcoded fallback list, an offline session, a /models fetch that
|
|
509
|
+
failed), falls back to a substring heuristic: any id containing `codex`
|
|
510
|
+
routes to `/responses`, since the entire Codex family only accepts that
|
|
511
|
+
endpoint. Everything else stays on `/chat/completions`.
|
|
512
|
+
"""
|
|
513
|
+
if model_id in copilot_model_endpoints:
|
|
514
|
+
return copilot_model_endpoints[model_id]
|
|
515
|
+
if "codex" in model_id.lower():
|
|
516
|
+
return _COPILOT_RESPONSES_ENDPOINT
|
|
517
|
+
return _COPILOT_CHAT_ENDPOINT
|
|
469
518
|
|
|
470
519
|
def get_token_thread_func():
|
|
471
520
|
global github_auth, get_token_thread, last_token_fetch_time
|
|
@@ -627,6 +676,309 @@ def _aggregate_streaming_response(client: sseclient.SSEClient) -> dict:
|
|
|
627
676
|
|
|
628
677
|
return _format_llm_response()
|
|
629
678
|
|
|
679
|
+
def _messages_to_responses_input(messages: list[dict]) -> tuple[list[dict], str | None]:
|
|
680
|
+
"""Translate an OpenAI chat-completions `messages` array into the shape
|
|
681
|
+
Copilot's `/responses` endpoint accepts.
|
|
682
|
+
|
|
683
|
+
System messages collapse into the top-level ``instructions`` field
|
|
684
|
+
(newline-joined when more than one is present). Assistant tool calls
|
|
685
|
+
expand to `function_call` items, tool results to `function_call_output`
|
|
686
|
+
items, and the remaining role/content pairs pass through with their
|
|
687
|
+
original role. Matches what codecompanion.nvim sends and what OpenAI's
|
|
688
|
+
own Responses migration guide documents.
|
|
689
|
+
"""
|
|
690
|
+
instructions_parts: list[str] = []
|
|
691
|
+
input_items: list[dict] = []
|
|
692
|
+
for msg in messages:
|
|
693
|
+
if not isinstance(msg, dict):
|
|
694
|
+
continue
|
|
695
|
+
role = msg.get("role")
|
|
696
|
+
content = msg.get("content")
|
|
697
|
+
if role == "system":
|
|
698
|
+
if isinstance(content, str) and content:
|
|
699
|
+
instructions_parts.append(content)
|
|
700
|
+
continue
|
|
701
|
+
if role == "tool":
|
|
702
|
+
output = content if isinstance(content, str) else json.dumps(content)
|
|
703
|
+
input_items.append({
|
|
704
|
+
"type": "function_call_output",
|
|
705
|
+
"call_id": msg.get("tool_call_id"),
|
|
706
|
+
"output": output,
|
|
707
|
+
})
|
|
708
|
+
continue
|
|
709
|
+
if role == "assistant" and msg.get("tool_calls"):
|
|
710
|
+
for tc in msg["tool_calls"]:
|
|
711
|
+
fn = (tc.get("function") or {}) if isinstance(tc, dict) else {}
|
|
712
|
+
call_id = tc.get("id") if isinstance(tc, dict) else None
|
|
713
|
+
input_items.append({
|
|
714
|
+
"type": "function_call",
|
|
715
|
+
"call_id": call_id,
|
|
716
|
+
"name": fn.get("name"),
|
|
717
|
+
"arguments": fn.get("arguments", ""),
|
|
718
|
+
})
|
|
719
|
+
if isinstance(content, str) and content:
|
|
720
|
+
input_items.append({"role": role, "content": content})
|
|
721
|
+
continue
|
|
722
|
+
input_items.append({"role": role, "content": content if content is not None else ""})
|
|
723
|
+
instructions = "\n".join(instructions_parts) if instructions_parts else None
|
|
724
|
+
return input_items, instructions
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
def _chat_tools_to_responses_tools(tools: list[dict] | None) -> list[dict] | None:
|
|
728
|
+
"""Flatten chat-completions tool schemas to Responses-API shape.
|
|
729
|
+
|
|
730
|
+
Chat completions nests under ``{type: "function", function: {name, ...}}``;
|
|
731
|
+
Responses expects the function fields at the top level. The transform is
|
|
732
|
+
purely structural so a caller can keep emitting one schema upstream.
|
|
733
|
+
"""
|
|
734
|
+
if not tools:
|
|
735
|
+
return None
|
|
736
|
+
out: list[dict] = []
|
|
737
|
+
for tool in tools:
|
|
738
|
+
if not isinstance(tool, dict) or tool.get("type") != "function":
|
|
739
|
+
out.append(tool)
|
|
740
|
+
continue
|
|
741
|
+
fn = tool.get("function") or {}
|
|
742
|
+
out.append({
|
|
743
|
+
"type": "function",
|
|
744
|
+
"name": fn.get("name"),
|
|
745
|
+
"description": fn.get("description"),
|
|
746
|
+
"parameters": fn.get("parameters"),
|
|
747
|
+
})
|
|
748
|
+
return out
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
# Responses-API SSE event types that mean the server gave up mid-stream.
|
|
752
|
+
# Treated as hard failures so callers see an exception instead of a silent
|
|
753
|
+
# empty assistant turn; `response.incomplete` (max-tokens cap, etc.) is
|
|
754
|
+
# included because Codex emits it in place of `response.completed` and the
|
|
755
|
+
# partial content alone isn't enough signal for the chat sidebar.
|
|
756
|
+
_RESPONSES_TERMINAL_ERROR_EVENTS = frozenset({
|
|
757
|
+
"response.failed",
|
|
758
|
+
"response.error",
|
|
759
|
+
"response.incomplete",
|
|
760
|
+
"error",
|
|
761
|
+
})
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
def _responses_error_message(chunk: dict) -> str:
|
|
765
|
+
"""Extract the most descriptive error string a `response.failed` /
|
|
766
|
+
`response.error` event carries. Falls back to the raw type when the
|
|
767
|
+
server omits a message field."""
|
|
768
|
+
if not isinstance(chunk, dict):
|
|
769
|
+
return "GitHub Copilot returned an unparseable error event."
|
|
770
|
+
response_obj = chunk.get("response") or {}
|
|
771
|
+
for source in (chunk, response_obj):
|
|
772
|
+
if not isinstance(source, dict):
|
|
773
|
+
continue
|
|
774
|
+
err = source.get("error") if isinstance(source.get("error"), dict) else None
|
|
775
|
+
if err:
|
|
776
|
+
msg = err.get("message") or err.get("code")
|
|
777
|
+
if isinstance(msg, str) and msg:
|
|
778
|
+
return msg
|
|
779
|
+
msg = source.get("message")
|
|
780
|
+
if isinstance(msg, str) and msg:
|
|
781
|
+
return msg
|
|
782
|
+
return f"GitHub Copilot Responses stream emitted {chunk.get('type', 'unknown')!r} without a message."
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
def _function_call_item_to_chat_tool(item: dict, *, fallback_arguments: str = "") -> dict | None:
|
|
786
|
+
"""Turn a Responses-API `function_call` output item into the
|
|
787
|
+
chat-completions tool_call shape the rest of the codebase expects.
|
|
788
|
+
Returns None if the item should be skipped (wrong type, in-progress
|
|
789
|
+
status).
|
|
790
|
+
"""
|
|
791
|
+
if not isinstance(item, dict) or item.get("type") != "function_call":
|
|
792
|
+
return None
|
|
793
|
+
if item.get("status") not in (None, "completed"):
|
|
794
|
+
return None
|
|
795
|
+
return {
|
|
796
|
+
"id": item.get("call_id") or item.get("id"),
|
|
797
|
+
"type": "function",
|
|
798
|
+
"function": {
|
|
799
|
+
"name": item.get("name") or "",
|
|
800
|
+
"arguments": item.get("arguments") or fallback_arguments or "{}",
|
|
801
|
+
},
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
def _aggregate_responses_streaming(client: sseclient.SSEClient) -> dict:
|
|
806
|
+
"""Drain a `/responses` SSE stream and return the same chat-completions
|
|
807
|
+
shape `_aggregate_streaming_response` emits, so callers see one wire
|
|
808
|
+
format regardless of which endpoint served the model.
|
|
809
|
+
"""
|
|
810
|
+
final_content = ""
|
|
811
|
+
final_tool_calls: list[dict] = []
|
|
812
|
+
# Some Codex variants stream function-call arguments incrementally as
|
|
813
|
+
# `response.function_call_arguments.delta` events and only ship a
|
|
814
|
+
# zero-byte `arguments` field in the terminal `response.completed`
|
|
815
|
+
# item. Accumulate by `item_id` so we can stitch them back together
|
|
816
|
+
# if the terminal payload comes through empty.
|
|
817
|
+
arg_buffers: dict[str, str] = {}
|
|
818
|
+
for event in client.events():
|
|
819
|
+
if not event.data:
|
|
820
|
+
continue
|
|
821
|
+
try:
|
|
822
|
+
chunk = json.loads(event.data)
|
|
823
|
+
except (ValueError, json.JSONDecodeError):
|
|
824
|
+
continue
|
|
825
|
+
event_type = chunk.get("type")
|
|
826
|
+
if event_type in _RESPONSES_TERMINAL_ERROR_EVENTS:
|
|
827
|
+
raise Exception(_responses_error_message(chunk))
|
|
828
|
+
if event_type == "response.output_text.delta":
|
|
829
|
+
delta = chunk.get("delta")
|
|
830
|
+
if isinstance(delta, str):
|
|
831
|
+
final_content += delta
|
|
832
|
+
elif event_type == "response.function_call_arguments.delta":
|
|
833
|
+
item_id = chunk.get("item_id")
|
|
834
|
+
delta = chunk.get("delta")
|
|
835
|
+
if isinstance(item_id, str) and isinstance(delta, str):
|
|
836
|
+
arg_buffers[item_id] = arg_buffers.get(item_id, "") + delta
|
|
837
|
+
elif event_type == "response.completed":
|
|
838
|
+
resp_obj = chunk.get("response") or {}
|
|
839
|
+
for item in resp_obj.get("output") or []:
|
|
840
|
+
if not isinstance(item, dict):
|
|
841
|
+
continue
|
|
842
|
+
buffered = arg_buffers.get(item.get("id") or "")
|
|
843
|
+
tc = _function_call_item_to_chat_tool(item, fallback_arguments=buffered or "")
|
|
844
|
+
if tc is not None:
|
|
845
|
+
final_tool_calls.append(tc)
|
|
846
|
+
break
|
|
847
|
+
return {
|
|
848
|
+
"choices": [{
|
|
849
|
+
"message": {
|
|
850
|
+
"role": "assistant",
|
|
851
|
+
"content": final_content,
|
|
852
|
+
"tool_calls": final_tool_calls if final_tool_calls else None,
|
|
853
|
+
}
|
|
854
|
+
}]
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
def responses(model_id, messages, tools = None, response: ChatResponse = None, cancel_token: CancelToken = None, options: dict = {}) -> Any:
|
|
859
|
+
"""Send a chat turn through Copilot's `/responses` endpoint.
|
|
860
|
+
|
|
861
|
+
Required for Codex-class models, which 400 on `/chat/completions`. The
|
|
862
|
+
aggregate and streaming return shapes match `completions()` so callers
|
|
863
|
+
don't need an endpoint branch above this layer.
|
|
864
|
+
"""
|
|
865
|
+
aggregate = response is None
|
|
866
|
+
|
|
867
|
+
try:
|
|
868
|
+
input_items, instructions = _messages_to_responses_input(messages)
|
|
869
|
+
data: dict[str, Any] = {
|
|
870
|
+
"model": model_id,
|
|
871
|
+
"input": input_items,
|
|
872
|
+
"stream": True,
|
|
873
|
+
}
|
|
874
|
+
if instructions:
|
|
875
|
+
data["instructions"] = instructions
|
|
876
|
+
responses_tools = _chat_tools_to_responses_tools(tools)
|
|
877
|
+
if responses_tools:
|
|
878
|
+
data["tools"] = responses_tools
|
|
879
|
+
if "tool_choice" in options:
|
|
880
|
+
data["tool_choice"] = options["tool_choice"]
|
|
881
|
+
|
|
882
|
+
if cancel_token is not None and cancel_token.is_cancel_requested:
|
|
883
|
+
if response is not None:
|
|
884
|
+
response.finish()
|
|
885
|
+
return
|
|
886
|
+
|
|
887
|
+
request = requests.post(
|
|
888
|
+
f"{API_ENDPOINT}{_COPILOT_RESPONSES_ENDPOINT}",
|
|
889
|
+
headers=generate_copilot_headers(),
|
|
890
|
+
json=data,
|
|
891
|
+
stream=True,
|
|
892
|
+
)
|
|
893
|
+
|
|
894
|
+
if request.status_code != 200:
|
|
895
|
+
msg = f"Failed to get responses from GitHub Copilot: [{request.status_code}]: {request.text}"
|
|
896
|
+
log.error(msg)
|
|
897
|
+
if response is not None:
|
|
898
|
+
response.stream(MarkdownData(msg))
|
|
899
|
+
response.finish()
|
|
900
|
+
raise Exception(msg)
|
|
901
|
+
|
|
902
|
+
client = sseclient.SSEClient(request)
|
|
903
|
+
if aggregate:
|
|
904
|
+
return _aggregate_responses_streaming(client)
|
|
905
|
+
|
|
906
|
+
# Streaming: translate typed Responses events into chat-completions
|
|
907
|
+
# delta chunks the existing frontend consumer already knows how to
|
|
908
|
+
# render. The shape `{choices: [{delta: {role, content}}]}` matches
|
|
909
|
+
# what `_aggregate_streaming_response` and `response.stream(...)`
|
|
910
|
+
# below produce for `/chat/completions`.
|
|
911
|
+
arg_buffers: dict[str, str] = {}
|
|
912
|
+
for event in client.events():
|
|
913
|
+
if cancel_token is not None and cancel_token.is_cancel_requested:
|
|
914
|
+
response.finish()
|
|
915
|
+
return
|
|
916
|
+
if not event.data:
|
|
917
|
+
continue
|
|
918
|
+
try:
|
|
919
|
+
chunk = json.loads(event.data)
|
|
920
|
+
except (ValueError, json.JSONDecodeError):
|
|
921
|
+
continue
|
|
922
|
+
event_type = chunk.get("type")
|
|
923
|
+
if event_type in _RESPONSES_TERMINAL_ERROR_EVENTS:
|
|
924
|
+
msg = _responses_error_message(chunk)
|
|
925
|
+
log.error(f"GitHub Copilot Responses stream failed: {msg}")
|
|
926
|
+
response.stream(MarkdownData(msg))
|
|
927
|
+
response.finish()
|
|
928
|
+
raise Exception(msg)
|
|
929
|
+
if event_type == "response.output_text.delta":
|
|
930
|
+
delta = chunk.get("delta")
|
|
931
|
+
if isinstance(delta, str) and delta:
|
|
932
|
+
response.stream({
|
|
933
|
+
"choices": [{
|
|
934
|
+
"delta": {"role": "assistant", "content": delta}
|
|
935
|
+
}]
|
|
936
|
+
})
|
|
937
|
+
elif event_type == "response.function_call_arguments.delta":
|
|
938
|
+
item_id = chunk.get("item_id")
|
|
939
|
+
delta = chunk.get("delta")
|
|
940
|
+
if isinstance(item_id, str) and isinstance(delta, str):
|
|
941
|
+
arg_buffers[item_id] = arg_buffers.get(item_id, "") + delta
|
|
942
|
+
elif event_type == "response.completed":
|
|
943
|
+
resp_obj = chunk.get("response") or {}
|
|
944
|
+
tool_calls: list[dict] = []
|
|
945
|
+
for idx, item in enumerate(resp_obj.get("output") or []):
|
|
946
|
+
if not isinstance(item, dict):
|
|
947
|
+
continue
|
|
948
|
+
buffered = arg_buffers.get(item.get("id") or "")
|
|
949
|
+
tc = _function_call_item_to_chat_tool(item, fallback_arguments=buffered or "")
|
|
950
|
+
if tc is None:
|
|
951
|
+
continue
|
|
952
|
+
tc["index"] = idx
|
|
953
|
+
tool_calls.append(tc)
|
|
954
|
+
if tool_calls:
|
|
955
|
+
response.stream({
|
|
956
|
+
"choices": [{
|
|
957
|
+
"delta": {"role": "assistant", "tool_calls": tool_calls}
|
|
958
|
+
}]
|
|
959
|
+
})
|
|
960
|
+
response.finish()
|
|
961
|
+
return
|
|
962
|
+
response.finish()
|
|
963
|
+
return
|
|
964
|
+
except requests.exceptions.ConnectionError:
|
|
965
|
+
raise Exception("Connection error")
|
|
966
|
+
except Exception as e:
|
|
967
|
+
log.error(f"Failed to get responses from GitHub Copilot: {e}")
|
|
968
|
+
raise e
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
def chat(model_id, messages, tools = None, response: ChatResponse = None, cancel_token: CancelToken = None, options: dict = {}) -> Any:
|
|
972
|
+
"""Endpoint-aware chat entry point. Routes Codex-class models to
|
|
973
|
+
`/responses` and everything else to `/chat/completions`. Callers from
|
|
974
|
+
the LLM provider should go through this rather than `completions(...)`
|
|
975
|
+
directly so per-model dispatch stays in one place.
|
|
976
|
+
"""
|
|
977
|
+
if _model_chat_endpoint(model_id) == _COPILOT_RESPONSES_ENDPOINT:
|
|
978
|
+
return responses(model_id, messages, tools, response, cancel_token, options)
|
|
979
|
+
return completions(model_id, messages, tools, response, cancel_token, options)
|
|
980
|
+
|
|
981
|
+
|
|
630
982
|
def completions(model_id, messages, tools = None, response: ChatResponse = None, cancel_token: CancelToken = None, options: dict = {}) -> Any:
|
|
631
983
|
aggregate = response is None
|
|
632
984
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plmbr/notebook-intelligence",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.1",
|
|
4
4
|
"description": "AI coding assistant for JupyterLab",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"AI",
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
}
|
|
150
150
|
},
|
|
151
151
|
"_build": {
|
|
152
|
-
"load": "static/remoteEntry.
|
|
152
|
+
"load": "static/remoteEntry.e77a2554241f4d36341c.js",
|
|
153
153
|
"extension": "./extension",
|
|
154
154
|
"style": "./style"
|
|
155
155
|
}
|