sage-agent-internal 0.2.5__tar.gz → 0.2.7__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.
Files changed (230) hide show
  1. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/.gitignore +1 -0
  2. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/PKG-INFO +1 -1
  3. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/package.json +1 -1
  4. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/_version.py +1 -1
  5. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/package.json +2 -2
  6. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/schemas/sage-agent-internal/package.json.orig +1 -1
  7. sage_agent_internal-0.2.5/sage_agent_internal/labextension/static/remoteEntry.c97bd67ec0a2caecdfcb.js → sage_agent_internal-0.2.7/sage_agent_internal/labextension/static/remoteEntry.18398c4b48f031899373.js +1 -1
  8. sage_agent_internal-0.2.7/ui-tests/README.md +22 -0
  9. sage_agent_internal-0.2.7/ui-tests/package.json +22 -0
  10. sage_agent_internal-0.2.7/ui-tests/playwright.config.js +30 -0
  11. sage_agent_internal-0.2.7/ui-tests/setup-tests.bat +38 -0
  12. sage_agent_internal-0.2.7/ui-tests/setup-tests.sh +36 -0
  13. sage_agent_internal-0.2.7/ui-tests/slack-test-README.md +44 -0
  14. sage_agent_internal-0.2.7/ui-tests/test_slack.py +245 -0
  15. sage_agent_internal-0.2.7/ui-tests/tests/README_SAGE_LLM_TESTS.md +133 -0
  16. sage_agent_internal-0.2.7/ui-tests/tests/SAGE_LLM_TESTING_PLAN.md +238 -0
  17. sage_agent_internal-0.2.7/ui-tests/tests/config-example.ts +64 -0
  18. sage_agent_internal-0.2.7/ui-tests/tests/sage_agent.spec.ts +55 -0
  19. sage_agent_internal-0.2.7/ui-tests/tests/sage_diff_interactions.spec.ts +571 -0
  20. sage_agent_internal-0.2.7/ui-tests/tests/sage_llm_test.spec.ts +814 -0
  21. sage_agent_internal-0.2.7/ui-tests/yarn.lock +5159 -0
  22. sage_agent_internal-0.2.5/ui-tests/README.md +0 -167
  23. sage_agent_internal-0.2.5/ui-tests/package.json +0 -15
  24. sage_agent_internal-0.2.5/ui-tests/playwright.config.js +0 -14
  25. sage_agent_internal-0.2.5/ui-tests/tests/sage_agent.spec.ts +0 -36
  26. sage_agent_internal-0.2.5/ui-tests/yarn.lock +0 -0
  27. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/.copier-answers.yml +0 -0
  28. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/.keep +0 -0
  29. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/.prettierignore +0 -0
  30. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/.vscode/settings.json +0 -0
  31. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/.yarnrc.yml +0 -0
  32. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/CHANGELOG.md +0 -0
  33. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/CLAUDE.md +0 -0
  34. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/LICENSE +0 -0
  35. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/README.md +0 -0
  36. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/RELEASE.md +0 -0
  37. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/__tests__/sage_agent.spec.ts +0 -0
  38. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/babel.config.js +0 -0
  39. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/cli-chat-tool/index.ts +0 -0
  40. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/cli-chat-tool/package-lock.json +0 -0
  41. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/cli-chat-tool/package.json +0 -0
  42. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/cli-chat-tool/tsconfig.json +0 -0
  43. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/cli-chat-tool/yarn.lock +0 -0
  44. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/install.json +0 -0
  45. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/jest.config.js +0 -0
  46. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/package-lock.json +0 -0
  47. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/pyproject.toml +0 -0
  48. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/__init__.py +0 -0
  49. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/schemas/sage-agent-internal/plugin.json +0 -0
  50. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/122.3c2c200586e65203b674.js +0 -0
  51. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/220.d384edfd5bbcfda33a2a.js +0 -0
  52. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/262.3fc4ad88e6f8c273d4ad.js +0 -0
  53. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/353.2c285601a208c3735929.js +0 -0
  54. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/363.6fc8d18eedbf137940f2.js +0 -0
  55. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/364.c2fb82c6f484097228c6.js +0 -0
  56. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/439.3cb9ac7022c8a6074647.js +0 -0
  57. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/481.96b91d018df31d54d173.js +0 -0
  58. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/553.b7906877d98a62265533.js +0 -0
  59. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/553.b7906877d98a62265533.js.LICENSE.txt +0 -0
  60. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/635.8c395c854aa2b140b668.js +0 -0
  61. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/713.103cb5ae248be385b08a.js +0 -0
  62. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/742.b204789055ded4e07883.js +0 -0
  63. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/747.b8e9485ebcbb3066eb4b.js +0 -0
  64. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/821.b58f29814f5900f1f6f8.js +0 -0
  65. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/845.cc2bc80fbfea6d20a396.js +0 -0
  66. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/888.09382cc93a2ad3932b31.js +0 -0
  67. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/968.980219bfdaa6b20f56cb.js +0 -0
  68. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/973.016a586759b281b79f91.js +0 -0
  69. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/973.016a586759b281b79f91.js.LICENSE.txt +0 -0
  70. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/style.js +0 -0
  71. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/sage_agent_internal/labextension/static/third-party-licenses.json +0 -0
  72. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/schema/plugin.json +0 -0
  73. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/setup.py +0 -0
  74. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/AppState.ts +0 -0
  75. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/BackendTools/DatabaseTools.ts +0 -0
  76. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/BackendTools/FilesystemTools.ts +0 -0
  77. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/BackendTools/WebTools.ts +0 -0
  78. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/BackendTools/index.ts +0 -0
  79. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/BackendTools/tickers.json +0 -0
  80. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/CellTrackingService.ts +0 -0
  81. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ActionHistory.ts +0 -0
  82. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ChatContextMenu/ChatContextLoaders.ts +0 -0
  83. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ChatContextMenu/ChatContextMenu.ts +0 -0
  84. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ChatContextMenu/ChatContextMenuLogic.ts +0 -0
  85. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ChatContextMenu/ChatContextMenuUtils.ts +0 -0
  86. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ChatContextMenu/ContextCacheService.ts +0 -0
  87. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ChatContextMenu/ContextCellHighlighter.ts +0 -0
  88. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ChatContextMenu/KernelExecutionListener.ts +0 -0
  89. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ChatContextMenu/icons.ts +0 -0
  90. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ChatHistoryManager.ts +0 -0
  91. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ChatInputManager.ts +0 -0
  92. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ChatMessages.ts +0 -0
  93. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ChatUIHelper.ts +0 -0
  94. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ConversationService.ts +0 -0
  95. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/ConversationServiceUtils.ts +0 -0
  96. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Chat/RichTextChatInput.ts +0 -0
  97. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/CodebaseManager.ts +0 -0
  98. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/ChatboxContext.ts +0 -0
  99. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/CodeConfirmationDialog.ts +0 -0
  100. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/DiffApprovalDialog.ts +0 -0
  101. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/DiffNavigationContent.tsx +0 -0
  102. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/DiffNavigationWidget.tsx +0 -0
  103. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/InlineCompletionWidget.tsx +0 -0
  104. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/LLMStateDisplay/DiffItem.tsx +0 -0
  105. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/LLMStateDisplay/LLMStateContent.tsx +0 -0
  106. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/LLMStateDisplay/LLMStateDisplay.tsx +0 -0
  107. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/LLMStateDisplay/icons.ts +0 -0
  108. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/LLMStateDisplay/index.ts +0 -0
  109. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/LLMStateDisplay/types.ts +0 -0
  110. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/MoreOptionsDisplay.tsx +0 -0
  111. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/NewChatDisplayWidget.ts +0 -0
  112. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/PlanStateDisplay.tsx +0 -0
  113. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/RejectionFeedbackDialog.ts +0 -0
  114. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/Settings/SettingsWidget.tsx +0 -0
  115. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/SnippetCreationWidget/SnippetCreationContent.tsx +0 -0
  116. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/SnippetCreationWidget/SnippetCreationWidget.tsx +0 -0
  117. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/SnippetCreationWidget/SnippetForm.tsx +0 -0
  118. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/SnippetCreationWidget/SnippetFormModal.tsx +0 -0
  119. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/SnippetCreationWidget/SnippetList.tsx +0 -0
  120. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/SnippetCreationWidget/index.ts +0 -0
  121. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/SnippetCreationWidget/types.ts +0 -0
  122. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/UpdateBanner/UpdateBannerWidget.tsx +0 -0
  123. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/chatbox.ts +0 -0
  124. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Components/icons.ts +0 -0
  125. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Config/ConfigService.ts +0 -0
  126. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Config/models.json +0 -0
  127. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Config/optional_env.json +0 -0
  128. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Config/prompts/claude_system_prompt.md +0 -0
  129. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Config/prompts/claude_system_prompt_ask_mode.md +0 -0
  130. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Config/prompts/claude_system_prompt_edit_full_cell.md +0 -0
  131. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Config/prompts/claude_system_prompt_edit_selection.md +0 -0
  132. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Config/prompts/claude_system_prompt_fast_mode.md +0 -0
  133. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Config/tools.json +0 -0
  134. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Notebook/InlineDiffService.ts +0 -0
  135. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Notebook/NotebookCellTools.ts +0 -0
  136. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Notebook/NotebookChatContainer.ts +0 -0
  137. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Notebook/NotebookContextManager.ts +0 -0
  138. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Notebook/NotebookDiffManager.ts +0 -0
  139. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Notebook/NotebookDiffTools.ts +0 -0
  140. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Notebook/NotebookStateService.ts +0 -0
  141. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Notebook/NotebookTools.ts +0 -0
  142. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Notebook/WaitingUserReplyBoxManager.ts +0 -0
  143. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/NotebookSettingsContainer.ts +0 -0
  144. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/AnthropicMessageCreator.ts +0 -0
  145. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/AnthropicService.ts +0 -0
  146. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/AnthropicStreamHandler.ts +0 -0
  147. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/CompletionManager.ts +0 -0
  148. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/ContextService.ts +0 -0
  149. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/DatabaseMetadataCache.ts +0 -0
  150. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/DiffStateService.ts +0 -0
  151. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/IChatService.ts +0 -0
  152. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/NotebookCellStateService.ts +0 -0
  153. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/ServiceFactory.ts +0 -0
  154. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/ServiceUtils.ts +0 -0
  155. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/TabCompletionService.ts +0 -0
  156. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/Services/ToolService.ts +0 -0
  157. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/ThreadManager.ts +0 -0
  158. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/TrackingIDUtility.ts +0 -0
  159. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/commands.ts +0 -0
  160. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/eval_commands.ts +0 -0
  161. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/index.ts +0 -0
  162. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/plugin.ts +0 -0
  163. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/types/json.d.ts +0 -0
  164. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/types.ts +0 -0
  165. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/utils/VariableExtractor.ts +0 -0
  166. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/utils/caching.ts +0 -0
  167. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/utils/contextTagUtils.ts +0 -0
  168. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/utils/kernelPreview.ts +0 -0
  169. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/utils/kernelUtils.ts +0 -0
  170. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/utils/stateDBCaching.ts +0 -0
  171. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/utils/tokenUtils.ts +0 -0
  172. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/utils/toolDisplay.ts +0 -0
  173. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/src/utils.ts +0 -0
  174. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/base.css +0 -0
  175. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/chat-container.css +0 -0
  176. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/chat-mention-dropdown.css +0 -0
  177. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/code-mirror-merge.css +0 -0
  178. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/codebase-manager.css +0 -0
  179. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/diff-approval.css +0 -0
  180. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/diff-edit-mode.css +0 -0
  181. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/diff-mode.css +0 -0
  182. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/diff-navigation.css +0 -0
  183. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/floating-bottom-widget.css +0 -0
  184. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/fonts.css +0 -0
  185. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/agent-mode-shiny.svg +0 -0
  186. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/agent-mode.svg +0 -0
  187. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/approve.svg +0 -0
  188. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/arrow-down.svg +0 -0
  189. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/arrow-up.svg +0 -0
  190. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/ask-mode.svg +0 -0
  191. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/check.svg +0 -0
  192. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/dashed-circle.svg +0 -0
  193. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/hands-on-mode.svg +0 -0
  194. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/open.svg +0 -0
  195. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/reapply.svg +0 -0
  196. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/reject.svg +0 -0
  197. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/run.svg +0 -0
  198. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/search.svg +0 -0
  199. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/send.svg +0 -0
  200. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/chat_input/stop.svg +0 -0
  201. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/context_menu/cell.svg +0 -0
  202. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/context_menu/data.svg +0 -0
  203. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/context_menu/insert.svg +0 -0
  204. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/context_menu/search.svg +0 -0
  205. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/context_menu/snippets.svg +0 -0
  206. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/context_menu/variable.svg +0 -0
  207. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/state_display/menu-close.svg +0 -0
  208. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/state_display/menu-icon.svg +0 -0
  209. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/icons/state_display/run_cell.svg +0 -0
  210. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/index.css +0 -0
  211. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/index.js +0 -0
  212. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/inline-diff-approval.css +0 -0
  213. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/left-side-menu.css +0 -0
  214. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/llm-state-display.css +0 -0
  215. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/minus-icon.css +0 -0
  216. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/modal.css +0 -0
  217. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/mode-selector-dropdown.css +0 -0
  218. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/more-options.css +0 -0
  219. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/new-chat-display.css +0 -0
  220. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/plan-state-display.css +0 -0
  221. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/settings-widget.css +0 -0
  222. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/snippet-creation.css +0 -0
  223. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/style.css +0 -0
  224. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/tab-completion.css +0 -0
  225. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/style/update-banner.css +0 -0
  226. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/templates/rule.example.md +0 -0
  227. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/tsconfig.json +0 -0
  228. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/tsconfig.test.json +0 -0
  229. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/ui-tests/jupyter_server_test_config.py +0 -0
  230. {sage_agent_internal-0.2.5 → sage_agent_internal-0.2.7}/yarn.lock +0 -0
@@ -127,3 +127,4 @@ dmypy.json
127
127
  *.ipynb
128
128
 
129
129
  .env
130
+ /ui-tests/test-results.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sage_agent_internal
3
- Version: 0.2.5
3
+ Version: 0.2.7
4
4
  Summary: Sage Agent - Your Jupyter Notebook Assistant
5
5
  Project-URL: Homepage, https://github.com/AlpineX-Labs/jupyter-sage-agent-internal
6
6
  Project-URL: Bug Tracker, https://github.com/AlpineX-Labs/jupyter-sage-agent-internal/issues
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sage-agent-internal",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Sage Agent - Your Jupyter Notebook Assistant",
5
5
  "keywords": [
6
6
  "jupyter",
@@ -1,4 +1,4 @@
1
1
  # This file is auto-generated by Hatchling. As such, do not:
2
2
  # - modify
3
3
  # - track in version control e.g. be sure to add to .gitignore
4
- __version__ = VERSION = '0.2.5'
4
+ __version__ = VERSION = '0.2.7'
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sage-agent-internal",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Sage Agent - Your Jupyter Notebook Assistant",
5
5
  "keywords": [
6
6
  "jupyter",
@@ -127,7 +127,7 @@
127
127
  "outputDir": "sage_agent_internal/labextension",
128
128
  "schemaDir": "schema",
129
129
  "_build": {
130
- "load": "static/remoteEntry.c97bd67ec0a2caecdfcb.js",
130
+ "load": "static/remoteEntry.18398c4b48f031899373.js",
131
131
  "extension": "./extension",
132
132
  "style": "./style"
133
133
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sage-agent-internal",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Sage Agent - Your Jupyter Notebook Assistant",
5
5
  "keywords": [
6
6
  "jupyter",
@@ -1 +1 @@
1
- var _JUPYTERLAB;(()=>{"use strict";var e,r,t,a,n,o,i,f,d,l,u,c,s,p,h,b,m,g,v,y,j,w,P,k,S,O={484:(e,r,t)=>{var a={"./index":()=>Promise.all([t.e(353),t.e(747),t.e(122),t.e(973),t.e(760),t.e(345),t.e(379),t.e(839),t.e(968)]).then(()=>()=>t(9040)),"./extension":()=>Promise.all([t.e(353),t.e(747),t.e(122),t.e(973),t.e(760),t.e(345),t.e(379),t.e(839),t.e(968)]).then(()=>()=>t(9040)),"./style":()=>t.e(363).then(()=>()=>t(8363))},n=(e,r)=>(t.R=r,r=t.o(a,e)?a[e]():Promise.resolve().then(()=>{throw new Error('Module "'+e+'" does not exist in container.')}),t.R=void 0,r),o=(e,r)=>{if(t.S){var a="default",n=t.S[a];if(n&&n!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[a]=e,t.I(a,r)}};t.d(r,{get:()=>n,init:()=>o})}},x={};function _(e){var r=x[e];if(void 0!==r)return r.exports;var t=x[e]={id:e,exports:{}};return O[e].call(t.exports,t,t.exports,_),t.exports}_.m=O,_.c=x,_.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return _.d(r,{a:r}),r},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,_.t=function(t,a){if(1&a&&(t=this(t)),8&a)return t;if("object"==typeof t&&t){if(4&a&&t.__esModule)return t;if(16&a&&"function"==typeof t.then)return t}var n=Object.create(null);_.r(n);var o={};e=e||[null,r({}),r([]),r(r)];for(var i=2&a&&t;("object"==typeof i||"function"==typeof i)&&!~e.indexOf(i);i=r(i))Object.getOwnPropertyNames(i).forEach(e=>o[e]=()=>t[e]);return o.default=()=>t,_.d(n,o),n},_.d=(e,r)=>{for(var t in r)_.o(r,t)&&!_.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},_.f={},_.e=e=>Promise.all(Object.keys(_.f).reduce((r,t)=>(_.f[t](e,r),r),[])),_.u=e=>e+"."+{122:"3c2c200586e65203b674",220:"d384edfd5bbcfda33a2a",262:"3fc4ad88e6f8c273d4ad",353:"2c285601a208c3735929",363:"6fc8d18eedbf137940f2",364:"c2fb82c6f484097228c6",439:"3cb9ac7022c8a6074647",481:"96b91d018df31d54d173",553:"b7906877d98a62265533",635:"8c395c854aa2b140b668",713:"103cb5ae248be385b08a",742:"b204789055ded4e07883",747:"b8e9485ebcbb3066eb4b",821:"b58f29814f5900f1f6f8",845:"cc2bc80fbfea6d20a396",888:"09382cc93a2ad3932b31",968:"980219bfdaa6b20f56cb",973:"016a586759b281b79f91"}[e]+".js?v="+{122:"3c2c200586e65203b674",220:"d384edfd5bbcfda33a2a",262:"3fc4ad88e6f8c273d4ad",353:"2c285601a208c3735929",363:"6fc8d18eedbf137940f2",364:"c2fb82c6f484097228c6",439:"3cb9ac7022c8a6074647",481:"96b91d018df31d54d173",553:"b7906877d98a62265533",635:"8c395c854aa2b140b668",713:"103cb5ae248be385b08a",742:"b204789055ded4e07883",747:"b8e9485ebcbb3066eb4b",821:"b58f29814f5900f1f6f8",845:"cc2bc80fbfea6d20a396",888:"09382cc93a2ad3932b31",968:"980219bfdaa6b20f56cb",973:"016a586759b281b79f91"}[e],_.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),_.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t={},a="sage-agent-internal:",_.l=(e,r,n,o)=>{if(t[e])t[e].push(r);else{var i,f;if(void 0!==n)for(var d=document.getElementsByTagName("script"),l=0;l<d.length;l++){var u=d[l];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==a+n){i=u;break}}i||(f=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,_.nc&&i.setAttribute("nonce",_.nc),i.setAttribute("data-webpack",a+n),i.src=e),t[e]=[r];var c=(r,a)=>{i.onerror=i.onload=null,clearTimeout(s);var n=t[e];if(delete t[e],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach(e=>e(a)),r)return r(a)},s=setTimeout(c.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=c.bind(null,i.onerror),i.onload=c.bind(null,i.onload),f&&document.head.appendChild(i)}},_.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{_.S={};var e={},r={};_.I=(t,a)=>{a||(a=[]);var n=r[t];if(n||(n=r[t]={}),!(a.indexOf(n)>=0)){if(a.push(n),e[t])return e[t];_.o(_.S,t)||(_.S[t]={});var o=_.S[t],i="sage-agent-internal",f=(e,r,t,a)=>{var n=o[e]=o[e]||{},f=n[r];(!f||!f.loaded&&(!a!=!f.eager?a:i>f.from))&&(n[r]={get:t,from:i,eager:!!a})},d=[];return"default"===t&&(f("@anthropic-ai/sdk","0.54.0",()=>_.e(742).then(()=>()=>_(2742))),f("best-effort-json-parser","1.2.1",()=>_.e(439).then(()=>()=>_(7820))),f("codemirror-merge-alpinex","6.10.4",()=>Promise.all([_.e(353),_.e(635),_.e(760),_.e(839)]).then(()=>()=>_(7635))),f("codemirror","6.0.2",()=>Promise.all([_.e(353),_.e(821),_.e(747),_.e(760)]).then(()=>()=>_(8821))),f("diff2html","3.4.52",()=>Promise.all([_.e(122),_.e(379)]).then(()=>()=>_(2122))),f("diff","7.0.0",()=>_.e(713).then(()=>()=>_(5713))),f("diff","0",()=>_.e(481).then(()=>()=>_(7481))),f("marked","15.0.12",()=>_.e(364).then(()=>()=>_(4364))),f("partial-json","0.1.7",()=>_.e(220).then(()=>()=>_(9220))),f("react-bootstrap","2.10.10",()=>Promise.all([_.e(553),_.e(345),_.e(628)]).then(()=>()=>_(4553))),f("rxjs","7.8.2",()=>_.e(888).then(()=>()=>_(2888))),f("sage-agent-internal","0.2.5",()=>Promise.all([_.e(353),_.e(747),_.e(122),_.e(973),_.e(760),_.e(345),_.e(379),_.e(839),_.e(968)]).then(()=>()=>_(9040))),f("uuid","11.1.0",()=>_.e(262).then(()=>()=>_(8262)))),e[t]=d.length?Promise.all(d).then(()=>e[t]=1):1}}})(),(()=>{var e;_.g.importScripts&&(e=_.g.location+"");var r=_.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var a=t.length-1;a>-1&&(!e||!/^http(s?):/.test(e));)e=t[a--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),_.p=e})(),n=e=>{var r=e=>e.split(".").map(e=>+e==e?+e:e),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),a=t[1]?r(t[1]):[];return t[2]&&(a.length++,a.push.apply(a,r(t[2]))),t[3]&&(a.push([]),a.push.apply(a,r(t[3]))),a},o=(e,r)=>{e=n(e),r=n(r);for(var t=0;;){if(t>=e.length)return t<r.length&&"u"!=(typeof r[t])[0];var a=e[t],o=(typeof a)[0];if(t>=r.length)return"u"==o;var i=r[t],f=(typeof i)[0];if(o!=f)return"o"==o&&"n"==f||"s"==f||"u"==o;if("o"!=o&&"u"!=o&&a!=i)return a<i;t++}},i=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var a=1,n=1;n<e.length;n++)a--,t+="u"==(typeof(f=e[n]))[0]?"-":(a>0?".":"")+(a=2,f);return t}var o=[];for(n=1;n<e.length;n++){var f=e[n];o.push(0===f?"not("+d()+")":1===f?"("+d()+" || "+d()+")":2===f?o.pop()+" "+o.pop():i(f))}return d();function d(){return o.pop().replace(/^\((.+)\)$/,"$1")}},f=(e,r)=>{if(0 in e){r=n(r);var t=e[0],a=t<0;a&&(t=-t-1);for(var o=0,i=1,d=!0;;i++,o++){var l,u,c=i<e.length?(typeof e[i])[0]:"";if(o>=r.length||"o"==(u=(typeof(l=r[o]))[0]))return!d||("u"==c?i>t&&!a:""==c!=a);if("u"==u){if(!d||"u"!=c)return!1}else if(d)if(c==u)if(i<=t){if(l!=e[i])return!1}else{if(a?l>e[i]:l<e[i])return!1;l!=e[i]&&(d=!1)}else if("s"!=c&&"n"!=c){if(a||i<=t)return!1;d=!1,i--}else{if(i<=t||u<c!=a)return!1;d=!1}else"s"!=c&&"n"!=c&&(d=!1,i--)}}var s=[],p=s.pop.bind(s);for(o=1;o<e.length;o++){var h=e[o];s.push(1==h?p()|p():2==h?p()&p():h?f(h,r):!p())}return!!p()},d=(e,r)=>e&&_.o(e,r),l=e=>(e.loaded=1,e.get()),u=e=>Object.keys(e).reduce((r,t)=>(e[t].eager&&(r[t]=e[t]),r),{}),c=(e,r,t,a)=>{var n=a?u(e[r]):e[r];return(r=Object.keys(n).reduce((e,r)=>!f(t,r)||e&&!o(e,r)?e:r,0))&&n[r]},s=(e,r,t)=>{var a=t?u(e[r]):e[r];return Object.keys(a).reduce((e,r)=>!e||!a[e].loaded&&o(e,r)?r:e,0)},p=(e,r,t,a)=>"Unsatisfied version "+t+" from "+(t&&e[r][t].from)+" of shared singleton module "+r+" (required "+i(a)+")",h=(e,r,t,a,n)=>{var o=e[t];return"No satisfying version ("+i(a)+")"+(n?" for eager consumption":"")+" of shared module "+t+" found in shared scope "+r+".\nAvailable versions: "+Object.keys(o).map(e=>e+" from "+o[e].from).join(", ")},b=e=>{throw new Error(e)},m=e=>{"undefined"!=typeof console&&console.warn&&console.warn(e)},v=(e,r,t)=>t?t():((e,r)=>b("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),y=(g=e=>function(r,t,a,n,o){var i=_.I(r);return i&&i.then&&!a?i.then(e.bind(e,r,_.S[r],t,!1,n,o)):e(r,_.S[r],t,a,n,o)})((e,r,t,a,n,o)=>{if(!d(r,t))return v(e,t,o);var i=c(r,t,n,a);return i?l(i):o?o():void b(h(r,e,t,n,a))}),j=g((e,r,t,a,n,o)=>{if(!d(r,t))return v(e,t,o);var i=s(r,t,a);return f(n,i)||m(p(r,t,i,n)),l(r[t][i])}),w={},P={195:()=>j("default","@codemirror/state",!1,[1,6,2,0]),2084:()=>j("default","@codemirror/language",!1,[1,6,0,0]),3708:()=>j("default","@lezer/common",!1,[1,1,0,0]),5024:()=>j("default","@codemirror/view",!1,[1,6,9,6]),3345:()=>j("default","react",!1,[1,18,2,0]),3379:()=>y("default","diff",!1,[1,7,0,0],()=>_.e(713).then(()=>()=>_(5713))),1839:()=>j("default","@lezer/highlight",!1,[1,1,0,0]),113:()=>y("default","diff",!1,[1,8,0,1],()=>_.e(481).then(()=>()=>_(7481))),135:()=>y("default","@anthropic-ai/sdk",!1,[2,0,54,0],()=>_.e(742).then(()=>()=>_(2742))),389:()=>j("default","@jupyterlab/statedb",!1,[1,4,4,6]),1336:()=>y("default","diff2html",!1,[1,3,4,51],()=>()=>_(2122)),2311:()=>y("default","react-bootstrap",!1,[1,2,10,10],()=>Promise.all([_.e(553),_.e(628)]).then(()=>()=>_(4553))),3139:()=>y("default","codemirror-merge-alpinex",!1,[1,6,10,4],()=>_.e(635).then(()=>()=>_(7635))),3427:()=>j("default","@jupyterlab/docmanager",!1,[1,4,4,6]),3550:()=>y("default","marked",!1,[1,15,0,11],()=>_.e(364).then(()=>()=>_(4364))),4602:()=>j("default","@lumino/signaling",!1,[1,2,0,0]),4744:()=>y("default","uuid",!1,[1,11,1,0],()=>_.e(262).then(()=>()=>_(8262))),5256:()=>j("default","@lumino/widgets",!1,[1,2,3,1,,"alpha",0]),5280:()=>j("default","@jupyterlab/extensionmanager",!1,[1,4,4,6]),6750:()=>y("default","rxjs",!1,[1,7,8,2],()=>_.e(888).then(()=>()=>_(2888))),7332:()=>y("default","codemirror",!1,[1,6,0,2],()=>_.e(821).then(()=>()=>_(8821))),7570:()=>y("default","partial-json",!1,[2,0,1,7],()=>_.e(220).then(()=>()=>_(9220))),8118:()=>j("default","@jupyterlab/codemirror",!1,[1,4,4,6]),8276:()=>y("default","best-effort-json-parser",!1,[1,1,1,3],()=>_.e(439).then(()=>()=>_(7820))),8361:()=>j("default","@jupyterlab/settingregistry",!1,[1,4,4,6]),8531:()=>j("default","@jupyterlab/notebook",!1,[1,4,4,6]),9159:()=>j("default","@jupyterlab/ui-components",!1,[1,4,4,6]),9715:()=>j("default","@jupyterlab/apputils",!1,[1,4,5,6]),7628:()=>j("default","react-dom",!1,[1,18,2,0])},k={345:[3345],379:[3379],628:[7628],760:[195,2084,3708,5024],839:[1839],968:[113,135,389,1336,2311,3139,3427,3550,4602,4744,5256,5280,6750,7332,7570,8118,8276,8361,8531,9159,9715]},S={},_.f.consumes=(e,r)=>{_.o(k,e)&&k[e].forEach(e=>{if(_.o(w,e))return r.push(w[e]);if(!S[e]){var t=r=>{w[e]=0,_.m[e]=t=>{delete _.c[e],t.exports=r()}};S[e]=!0;var a=r=>{delete w[e],_.m[e]=t=>{throw delete _.c[e],r}};try{var n=P[e]();n.then?r.push(w[e]=n.then(t).catch(a)):t(n)}catch(e){a(e)}}})},(()=>{_.b=document.baseURI||self.location.href;var e={431:0};_.f.j=(r,t)=>{var a=_.o(e,r)?e[r]:void 0;if(0!==a)if(a)t.push(a[2]);else if(/^(345|379|628|760|839)$/.test(r))e[r]=0;else{var n=new Promise((t,n)=>a=e[r]=[t,n]);t.push(a[2]=n);var o=_.p+_.u(r),i=new Error;_.l(o,t=>{if(_.o(e,r)&&(0!==(a=e[r])&&(e[r]=void 0),a)){var n=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+n+": "+o+")",i.name="ChunkLoadError",i.type=n,i.request=o,a[1](i)}},"chunk-"+r,r)}};var r=(r,t)=>{var a,n,[o,i,f]=t,d=0;if(o.some(r=>0!==e[r])){for(a in i)_.o(i,a)&&(_.m[a]=i[a]);f&&f(_)}for(r&&r(t);d<o.length;d++)n=o[d],_.o(e,n)&&e[n]&&e[n][0](),e[n]=0},t=self.webpackChunksage_agent_internal=self.webpackChunksage_agent_internal||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),_.nc=void 0;var E=_(484);(_JUPYTERLAB=void 0===_JUPYTERLAB?{}:_JUPYTERLAB)["sage-agent-internal"]=E})();
1
+ var _JUPYTERLAB;(()=>{"use strict";var e,r,t,a,n,o,i,f,d,l,u,c,s,p,h,b,m,g,v,y,j,w,P,k,S,O={484:(e,r,t)=>{var a={"./index":()=>Promise.all([t.e(353),t.e(747),t.e(122),t.e(973),t.e(760),t.e(345),t.e(379),t.e(839),t.e(968)]).then(()=>()=>t(9040)),"./extension":()=>Promise.all([t.e(353),t.e(747),t.e(122),t.e(973),t.e(760),t.e(345),t.e(379),t.e(839),t.e(968)]).then(()=>()=>t(9040)),"./style":()=>t.e(363).then(()=>()=>t(8363))},n=(e,r)=>(t.R=r,r=t.o(a,e)?a[e]():Promise.resolve().then(()=>{throw new Error('Module "'+e+'" does not exist in container.')}),t.R=void 0,r),o=(e,r)=>{if(t.S){var a="default",n=t.S[a];if(n&&n!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[a]=e,t.I(a,r)}};t.d(r,{get:()=>n,init:()=>o})}},x={};function _(e){var r=x[e];if(void 0!==r)return r.exports;var t=x[e]={id:e,exports:{}};return O[e].call(t.exports,t,t.exports,_),t.exports}_.m=O,_.c=x,_.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return _.d(r,{a:r}),r},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,_.t=function(t,a){if(1&a&&(t=this(t)),8&a)return t;if("object"==typeof t&&t){if(4&a&&t.__esModule)return t;if(16&a&&"function"==typeof t.then)return t}var n=Object.create(null);_.r(n);var o={};e=e||[null,r({}),r([]),r(r)];for(var i=2&a&&t;("object"==typeof i||"function"==typeof i)&&!~e.indexOf(i);i=r(i))Object.getOwnPropertyNames(i).forEach(e=>o[e]=()=>t[e]);return o.default=()=>t,_.d(n,o),n},_.d=(e,r)=>{for(var t in r)_.o(r,t)&&!_.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},_.f={},_.e=e=>Promise.all(Object.keys(_.f).reduce((r,t)=>(_.f[t](e,r),r),[])),_.u=e=>e+"."+{122:"3c2c200586e65203b674",220:"d384edfd5bbcfda33a2a",262:"3fc4ad88e6f8c273d4ad",353:"2c285601a208c3735929",363:"6fc8d18eedbf137940f2",364:"c2fb82c6f484097228c6",439:"3cb9ac7022c8a6074647",481:"96b91d018df31d54d173",553:"b7906877d98a62265533",635:"8c395c854aa2b140b668",713:"103cb5ae248be385b08a",742:"b204789055ded4e07883",747:"b8e9485ebcbb3066eb4b",821:"b58f29814f5900f1f6f8",845:"cc2bc80fbfea6d20a396",888:"09382cc93a2ad3932b31",968:"980219bfdaa6b20f56cb",973:"016a586759b281b79f91"}[e]+".js?v="+{122:"3c2c200586e65203b674",220:"d384edfd5bbcfda33a2a",262:"3fc4ad88e6f8c273d4ad",353:"2c285601a208c3735929",363:"6fc8d18eedbf137940f2",364:"c2fb82c6f484097228c6",439:"3cb9ac7022c8a6074647",481:"96b91d018df31d54d173",553:"b7906877d98a62265533",635:"8c395c854aa2b140b668",713:"103cb5ae248be385b08a",742:"b204789055ded4e07883",747:"b8e9485ebcbb3066eb4b",821:"b58f29814f5900f1f6f8",845:"cc2bc80fbfea6d20a396",888:"09382cc93a2ad3932b31",968:"980219bfdaa6b20f56cb",973:"016a586759b281b79f91"}[e],_.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),_.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t={},a="sage-agent-internal:",_.l=(e,r,n,o)=>{if(t[e])t[e].push(r);else{var i,f;if(void 0!==n)for(var d=document.getElementsByTagName("script"),l=0;l<d.length;l++){var u=d[l];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==a+n){i=u;break}}i||(f=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,_.nc&&i.setAttribute("nonce",_.nc),i.setAttribute("data-webpack",a+n),i.src=e),t[e]=[r];var c=(r,a)=>{i.onerror=i.onload=null,clearTimeout(s);var n=t[e];if(delete t[e],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach(e=>e(a)),r)return r(a)},s=setTimeout(c.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=c.bind(null,i.onerror),i.onload=c.bind(null,i.onload),f&&document.head.appendChild(i)}},_.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{_.S={};var e={},r={};_.I=(t,a)=>{a||(a=[]);var n=r[t];if(n||(n=r[t]={}),!(a.indexOf(n)>=0)){if(a.push(n),e[t])return e[t];_.o(_.S,t)||(_.S[t]={});var o=_.S[t],i="sage-agent-internal",f=(e,r,t,a)=>{var n=o[e]=o[e]||{},f=n[r];(!f||!f.loaded&&(!a!=!f.eager?a:i>f.from))&&(n[r]={get:t,from:i,eager:!!a})},d=[];return"default"===t&&(f("@anthropic-ai/sdk","0.54.0",()=>_.e(742).then(()=>()=>_(2742))),f("best-effort-json-parser","1.2.1",()=>_.e(439).then(()=>()=>_(7820))),f("codemirror-merge-alpinex","6.10.4",()=>Promise.all([_.e(353),_.e(635),_.e(760),_.e(839)]).then(()=>()=>_(7635))),f("codemirror","6.0.2",()=>Promise.all([_.e(353),_.e(821),_.e(747),_.e(760)]).then(()=>()=>_(8821))),f("diff2html","3.4.52",()=>Promise.all([_.e(122),_.e(379)]).then(()=>()=>_(2122))),f("diff","7.0.0",()=>_.e(713).then(()=>()=>_(5713))),f("diff","0",()=>_.e(481).then(()=>()=>_(7481))),f("marked","15.0.12",()=>_.e(364).then(()=>()=>_(4364))),f("partial-json","0.1.7",()=>_.e(220).then(()=>()=>_(9220))),f("react-bootstrap","2.10.10",()=>Promise.all([_.e(553),_.e(345),_.e(628)]).then(()=>()=>_(4553))),f("rxjs","7.8.2",()=>_.e(888).then(()=>()=>_(2888))),f("sage-agent-internal","0.2.7",()=>Promise.all([_.e(353),_.e(747),_.e(122),_.e(973),_.e(760),_.e(345),_.e(379),_.e(839),_.e(968)]).then(()=>()=>_(9040))),f("uuid","11.1.0",()=>_.e(262).then(()=>()=>_(8262)))),e[t]=d.length?Promise.all(d).then(()=>e[t]=1):1}}})(),(()=>{var e;_.g.importScripts&&(e=_.g.location+"");var r=_.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var a=t.length-1;a>-1&&(!e||!/^http(s?):/.test(e));)e=t[a--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),_.p=e})(),n=e=>{var r=e=>e.split(".").map(e=>+e==e?+e:e),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),a=t[1]?r(t[1]):[];return t[2]&&(a.length++,a.push.apply(a,r(t[2]))),t[3]&&(a.push([]),a.push.apply(a,r(t[3]))),a},o=(e,r)=>{e=n(e),r=n(r);for(var t=0;;){if(t>=e.length)return t<r.length&&"u"!=(typeof r[t])[0];var a=e[t],o=(typeof a)[0];if(t>=r.length)return"u"==o;var i=r[t],f=(typeof i)[0];if(o!=f)return"o"==o&&"n"==f||"s"==f||"u"==o;if("o"!=o&&"u"!=o&&a!=i)return a<i;t++}},i=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var a=1,n=1;n<e.length;n++)a--,t+="u"==(typeof(f=e[n]))[0]?"-":(a>0?".":"")+(a=2,f);return t}var o=[];for(n=1;n<e.length;n++){var f=e[n];o.push(0===f?"not("+d()+")":1===f?"("+d()+" || "+d()+")":2===f?o.pop()+" "+o.pop():i(f))}return d();function d(){return o.pop().replace(/^\((.+)\)$/,"$1")}},f=(e,r)=>{if(0 in e){r=n(r);var t=e[0],a=t<0;a&&(t=-t-1);for(var o=0,i=1,d=!0;;i++,o++){var l,u,c=i<e.length?(typeof e[i])[0]:"";if(o>=r.length||"o"==(u=(typeof(l=r[o]))[0]))return!d||("u"==c?i>t&&!a:""==c!=a);if("u"==u){if(!d||"u"!=c)return!1}else if(d)if(c==u)if(i<=t){if(l!=e[i])return!1}else{if(a?l>e[i]:l<e[i])return!1;l!=e[i]&&(d=!1)}else if("s"!=c&&"n"!=c){if(a||i<=t)return!1;d=!1,i--}else{if(i<=t||u<c!=a)return!1;d=!1}else"s"!=c&&"n"!=c&&(d=!1,i--)}}var s=[],p=s.pop.bind(s);for(o=1;o<e.length;o++){var h=e[o];s.push(1==h?p()|p():2==h?p()&p():h?f(h,r):!p())}return!!p()},d=(e,r)=>e&&_.o(e,r),l=e=>(e.loaded=1,e.get()),u=e=>Object.keys(e).reduce((r,t)=>(e[t].eager&&(r[t]=e[t]),r),{}),c=(e,r,t,a)=>{var n=a?u(e[r]):e[r];return(r=Object.keys(n).reduce((e,r)=>!f(t,r)||e&&!o(e,r)?e:r,0))&&n[r]},s=(e,r,t)=>{var a=t?u(e[r]):e[r];return Object.keys(a).reduce((e,r)=>!e||!a[e].loaded&&o(e,r)?r:e,0)},p=(e,r,t,a)=>"Unsatisfied version "+t+" from "+(t&&e[r][t].from)+" of shared singleton module "+r+" (required "+i(a)+")",h=(e,r,t,a,n)=>{var o=e[t];return"No satisfying version ("+i(a)+")"+(n?" for eager consumption":"")+" of shared module "+t+" found in shared scope "+r+".\nAvailable versions: "+Object.keys(o).map(e=>e+" from "+o[e].from).join(", ")},b=e=>{throw new Error(e)},m=e=>{"undefined"!=typeof console&&console.warn&&console.warn(e)},v=(e,r,t)=>t?t():((e,r)=>b("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),y=(g=e=>function(r,t,a,n,o){var i=_.I(r);return i&&i.then&&!a?i.then(e.bind(e,r,_.S[r],t,!1,n,o)):e(r,_.S[r],t,a,n,o)})((e,r,t,a,n,o)=>{if(!d(r,t))return v(e,t,o);var i=c(r,t,n,a);return i?l(i):o?o():void b(h(r,e,t,n,a))}),j=g((e,r,t,a,n,o)=>{if(!d(r,t))return v(e,t,o);var i=s(r,t,a);return f(n,i)||m(p(r,t,i,n)),l(r[t][i])}),w={},P={195:()=>j("default","@codemirror/state",!1,[1,6,2,0]),2084:()=>j("default","@codemirror/language",!1,[1,6,0,0]),3708:()=>j("default","@lezer/common",!1,[1,1,0,0]),5024:()=>j("default","@codemirror/view",!1,[1,6,9,6]),3345:()=>j("default","react",!1,[1,18,2,0]),3379:()=>y("default","diff",!1,[1,7,0,0],()=>_.e(713).then(()=>()=>_(5713))),1839:()=>j("default","@lezer/highlight",!1,[1,1,0,0]),113:()=>y("default","diff",!1,[1,8,0,1],()=>_.e(481).then(()=>()=>_(7481))),135:()=>y("default","@anthropic-ai/sdk",!1,[2,0,54,0],()=>_.e(742).then(()=>()=>_(2742))),389:()=>j("default","@jupyterlab/statedb",!1,[1,4,4,6]),1336:()=>y("default","diff2html",!1,[1,3,4,51],()=>()=>_(2122)),2311:()=>y("default","react-bootstrap",!1,[1,2,10,10],()=>Promise.all([_.e(553),_.e(628)]).then(()=>()=>_(4553))),3139:()=>y("default","codemirror-merge-alpinex",!1,[1,6,10,4],()=>_.e(635).then(()=>()=>_(7635))),3427:()=>j("default","@jupyterlab/docmanager",!1,[1,4,4,6]),3550:()=>y("default","marked",!1,[1,15,0,11],()=>_.e(364).then(()=>()=>_(4364))),4602:()=>j("default","@lumino/signaling",!1,[1,2,0,0]),4744:()=>y("default","uuid",!1,[1,11,1,0],()=>_.e(262).then(()=>()=>_(8262))),5256:()=>j("default","@lumino/widgets",!1,[1,2,3,1,,"alpha",0]),5280:()=>j("default","@jupyterlab/extensionmanager",!1,[1,4,4,6]),6750:()=>y("default","rxjs",!1,[1,7,8,2],()=>_.e(888).then(()=>()=>_(2888))),7332:()=>y("default","codemirror",!1,[1,6,0,2],()=>_.e(821).then(()=>()=>_(8821))),7570:()=>y("default","partial-json",!1,[2,0,1,7],()=>_.e(220).then(()=>()=>_(9220))),8118:()=>j("default","@jupyterlab/codemirror",!1,[1,4,4,6]),8276:()=>y("default","best-effort-json-parser",!1,[1,1,1,3],()=>_.e(439).then(()=>()=>_(7820))),8361:()=>j("default","@jupyterlab/settingregistry",!1,[1,4,4,6]),8531:()=>j("default","@jupyterlab/notebook",!1,[1,4,4,6]),9159:()=>j("default","@jupyterlab/ui-components",!1,[1,4,4,6]),9715:()=>j("default","@jupyterlab/apputils",!1,[1,4,5,6]),7628:()=>j("default","react-dom",!1,[1,18,2,0])},k={345:[3345],379:[3379],628:[7628],760:[195,2084,3708,5024],839:[1839],968:[113,135,389,1336,2311,3139,3427,3550,4602,4744,5256,5280,6750,7332,7570,8118,8276,8361,8531,9159,9715]},S={},_.f.consumes=(e,r)=>{_.o(k,e)&&k[e].forEach(e=>{if(_.o(w,e))return r.push(w[e]);if(!S[e]){var t=r=>{w[e]=0,_.m[e]=t=>{delete _.c[e],t.exports=r()}};S[e]=!0;var a=r=>{delete w[e],_.m[e]=t=>{throw delete _.c[e],r}};try{var n=P[e]();n.then?r.push(w[e]=n.then(t).catch(a)):t(n)}catch(e){a(e)}}})},(()=>{_.b=document.baseURI||self.location.href;var e={431:0};_.f.j=(r,t)=>{var a=_.o(e,r)?e[r]:void 0;if(0!==a)if(a)t.push(a[2]);else if(/^(345|379|628|760|839)$/.test(r))e[r]=0;else{var n=new Promise((t,n)=>a=e[r]=[t,n]);t.push(a[2]=n);var o=_.p+_.u(r),i=new Error;_.l(o,t=>{if(_.o(e,r)&&(0!==(a=e[r])&&(e[r]=void 0),a)){var n=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+n+": "+o+")",i.name="ChunkLoadError",i.type=n,i.request=o,a[1](i)}},"chunk-"+r,r)}};var r=(r,t)=>{var a,n,[o,i,f]=t,d=0;if(o.some(r=>0!==e[r])){for(a in i)_.o(i,a)&&(_.m[a]=i[a]);f&&f(_)}for(r&&r(t);d<o.length;d++)n=o[d],_.o(e,n)&&e[n]&&e[n][0](),e[n]=0},t=self.webpackChunksage_agent_internal=self.webpackChunksage_agent_internal||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),_.nc=void 0;var E=_(484);(_JUPYTERLAB=void 0===_JUPYTERLAB?{}:_JUPYTERLAB)["sage-agent-internal"]=E})();
@@ -0,0 +1,22 @@
1
+
2
+ # Running Sage_AI Tests
3
+
4
+ ## Step 1: Configure `config.ts`
5
+ Copy the example config file:
6
+
7
+ ```bash
8
+ cp tests/config-example.ts tests/config.ts
9
+ ```
10
+ ## Step 2: Add Configs
11
+
12
+ Update `tests/config.ts` with your API key and other required configs.
13
+
14
+ ## Step 3: Install & Run Tests
15
+
16
+ Navigate to the UI tests folder, install dependencies, and run the tests:
17
+
18
+ ```bash
19
+ cd jupyter-sage-agent-internal/ui-tests
20
+ jlpm install
21
+ jlpm run test
22
+ ```
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "sage-agent-internal-ui-tests",
3
+ "version": "1.0.0",
4
+ "description": "JupyterLab sage-agent-internal Integration Tests",
5
+ "private": true,
6
+ "scripts": {
7
+ "start": "jupyter lab --config jupyter_server_test_config.py",
8
+ "clean:screenshots": "node -e \"const fs = require('fs'); const path = require('path'); const screenshotsDir = path.join(__dirname, 'screenshots'); if (fs.existsSync(screenshotsDir)) { fs.rmSync(screenshotsDir, { recursive: true, force: true }); console.log('Screenshots directory cleaned'); } else { console.log('Screenshots directory does not exist'); }\"",
9
+ "test": "npm run clean:screenshots && jlpm playwright test sage_diff_interactions",
10
+ "test:update": "npm run clean:screenshots && jlpm playwright test --update-snapshots",
11
+ "test:llm": "npm run clean:screenshots && jlpm playwright test sage_llm_test",
12
+ "test:diffs": "npm run clean:screenshots && jlpm playwright test sage_diff_interactions",
13
+ "test:headed": "npm run clean:screenshots && jlpm playwright test --headed",
14
+ "test:debug": "npm run clean:screenshots && jlpm playwright test --debug",
15
+ "setup": "echo '✅ Setup complete! Please edit tests/config.ts with your API key.'"
16
+ },
17
+ "devDependencies": {
18
+ "@jupyterlab/galata": "^5.0.5",
19
+ "@playwright/test": "^1.37.0",
20
+ "@types/node": "^20.0.0"
21
+ }
22
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Configuration for Playwright using default from @jupyterlab/galata
3
+ */
4
+ const baseConfig = require('@jupyterlab/galata/lib/playwright-config');
5
+
6
+ module.exports = {
7
+ ...baseConfig,
8
+ // Add 1 retry for each test
9
+ retries: 1,
10
+ use: {
11
+ ...baseConfig.use,
12
+ headless: true,
13
+ viewport: { width: 1920, height: 1080 }
14
+ },
15
+ video: {
16
+ size: { width: 1920, height: 1080 }
17
+ },
18
+ // Add multiple reporters for better CI integration
19
+ reporter: [
20
+ ['html'], // Keep the existing HTML reporter
21
+ ['json', { outputFile: 'test-results.json' }], // Add JSON reporter for easier parsing
22
+ ['list'] // Add list reporter for console output
23
+ ],
24
+ webServer: {
25
+ command: 'jlpm start',
26
+ url: 'http://localhost:8888/lab',
27
+ timeout: 120 * 1000,
28
+ reuseExistingServer: !process.env.CI
29
+ }
30
+ };
@@ -0,0 +1,38 @@
1
+ @echo off
2
+ REM Sage LLM Test Setup Script for Windows
3
+ REM This script helps set up the testing environment
4
+
5
+ echo 🚀 Setting up Sage LLM Test Environment
6
+
7
+ REM Configuration is now handled via tests/config.ts
8
+ echo 📝 Configuration is managed in tests/config.ts
9
+ echo ⚠️ IMPORTANT: Please edit tests/config.ts and set your API key before running tests!
10
+ echo Update SAGE_API_KEY in tests/config.ts with your actual API key
11
+
12
+ REM Check if node_modules exists
13
+ if not exist "node_modules" (
14
+ echo 📦 Installing dependencies...
15
+ npm install
16
+ ) else (
17
+ echo ✅ Dependencies already installed
18
+ )
19
+
20
+ REM Create screenshots directory
21
+ if not exist "screenshots" (
22
+ echo 📁 Creating screenshots directory...
23
+ mkdir screenshots\states\idle
24
+ mkdir screenshots\states\diff_approval
25
+ mkdir screenshots\states\interaction
26
+ mkdir screenshots\states\generation
27
+ mkdir screenshots\test_runs
28
+ ) else (
29
+ echo ✅ Screenshots directory already exists
30
+ )
31
+
32
+ echo.
33
+ echo 🎯 Setup complete! To run the tests:
34
+ echo 1. Make sure your API key is set in tests/config.ts
35
+ echo 2. Start JupyterLab: npm run start
36
+ echo 3. In another terminal, run tests: npm test
37
+ echo.
38
+ echo 📸 Screenshots will be saved in the screenshots\ directory
@@ -0,0 +1,36 @@
1
+ #!/bin/bash
2
+
3
+ # Sage LLM Test Setup Script
4
+ # This script helps set up the testing environment
5
+
6
+ echo "🚀 Setting up Sage LLM Test Environment"
7
+
8
+ # Configuration is now handled via tests/config.ts
9
+ echo "📝 Configuration is managed in tests/config.ts"
10
+ echo "⚠️ IMPORTANT: Please edit tests/config.ts and set your API key before running tests!"
11
+ echo " Update SAGE_API_KEY in tests/config.ts with your actual API key"
12
+
13
+ # Check if node_modules exists
14
+ if [ ! -d "node_modules" ]; then
15
+ echo "📦 Installing dependencies..."
16
+ npm install
17
+ else
18
+ echo "✅ Dependencies already installed"
19
+ fi
20
+
21
+ # Create screenshots directory
22
+ if [ ! -d "screenshots" ]; then
23
+ echo "📁 Creating screenshots directory..."
24
+ mkdir -p screenshots/states/{idle,diff_approval,interaction,generation}
25
+ mkdir -p screenshots/test_runs
26
+ else
27
+ echo "✅ Screenshots directory already exists"
28
+ fi
29
+
30
+ echo ""
31
+ echo "🎯 Setup complete! To run the tests:"
32
+ echo " 1. Make sure your API key is set in tests/config.ts"
33
+ echo " 2. Start JupyterLab: npm run start"
34
+ echo " 3. In another terminal, run tests: npm test"
35
+ echo ""
36
+ echo "📸 Screenshots will be saved in the screenshots/ directory"
@@ -0,0 +1,44 @@
1
+ # Slack Test Notification
2
+
3
+ This script (`test_slack.py`) is used to post UI test results to Slack channels as part of the GitHub Actions workflow.
4
+
5
+ ## How it works
6
+
7
+ 1. **Triggered by GitHub Actions**: The script runs at the end of the `run-tests.yml` workflow
8
+ 2. **Reads test results**: It reads the `test-summary.md` file generated by the test suite
9
+ 3. **Posts to Slack**: It posts the test results along with PR information to all accessible Slack channels
10
+
11
+ ## Configuration
12
+
13
+ The script requires the following environment variables to be set in GitHub repository secrets:
14
+
15
+ - `SLACK_BOT_TOKEN`: The Slack bot token for authentication
16
+
17
+ The following environment variables are automatically set by GitHub Actions:
18
+ - `GITHUB_PR_NUMBER`: Pull request number
19
+ - `GITHUB_PR_URL`: Pull request URL
20
+ - `GITHUB_REPOSITORY`: Repository name
21
+
22
+ ## Slack Bot Setup
23
+
24
+ To use this script, you need to:
25
+
26
+ 1. Create a Slack app and bot in your workspace
27
+ 2. Add the bot to the channels where you want notifications
28
+ 3. Set the `SLACK_BOT_TOKEN` secret in your GitHub repository settings
29
+
30
+ ## Message Format
31
+
32
+ The script posts a formatted message containing:
33
+ - PR number and link
34
+ - Repository name
35
+ - Complete test results summary (same content as GitHub comment)
36
+ - Test statistics (passed/failed/skipped)
37
+ - Links to artifacts and workflow run
38
+
39
+ ## Dependencies
40
+
41
+ - `slack-sdk`: For Slack API communication
42
+ - `python-dotenv`: For environment variable handling
43
+
44
+ Both are automatically installed by the GitHub Actions workflow.
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Slack bot for posting UI test results to Slack channels.
4
+ This script posts test results and PR links to Slack.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import time
10
+ import requests
11
+ from slack_sdk import WebClient
12
+ from slack_sdk.errors import SlackApiError
13
+ def get_pr_info():
14
+ """Get PR information from environment variables set by GitHub Actions."""
15
+ pr_number = os.environ.get("GITHUB_PR_NUMBER", "")
16
+ pr_url = os.environ.get("GITHUB_PR_URL", "")
17
+ repo_name = os.environ.get("GITHUB_REPOSITORY", "")
18
+ return pr_number, pr_url, repo_name
19
+
20
+ def get_test_results_content():
21
+ """Read the test summary content that would be posted to GitHub."""
22
+ summary_path = "./test-summary.md"
23
+
24
+ try:
25
+ if os.path.exists(summary_path):
26
+ with open(summary_path, 'r', encoding='utf-8') as f:
27
+ return f.read()
28
+ else:
29
+ return "❌ **Test Summary Not Available**\n\nTest summary file was not generated."
30
+ except Exception as e:
31
+ print(f"Error reading test summary: {e}")
32
+ return f"❌ **Error Reading Test Summary**\n\nFailed to read test summary file: {str(e)}"
33
+
34
+ def format_slack_message(pr_number, pr_url, repo_name, test_content):
35
+ """Format the message for Slack with PR info and test results."""
36
+ if pr_number and pr_url:
37
+ header = f"🔄 *UI Test Results for PR #{pr_number}*\n"
38
+ header += f"📋 *Repository:* {repo_name}\n"
39
+ header += f"🔗 *PR Link:* <{pr_url}|View Pull Request>\n\n"
40
+ else:
41
+ header = f"🔄 *UI Test Results*\n"
42
+ header += f"📋 *Repository:* {repo_name}\n\n"
43
+
44
+ # Convert markdown to Slack-friendly format
45
+ slack_content = test_content
46
+ # Convert markdown headers to bold text
47
+ slack_content = slack_content.replace("## ", "*").replace("#", "*")
48
+ # Convert markdown bold to Slack bold
49
+ slack_content = slack_content.replace("**", "*")
50
+ # Convert markdown links to Slack format where possible
51
+ # Note: This is a basic conversion, more complex regex might be needed
52
+
53
+ message = header + slack_content
54
+
55
+ # Slack has a 4000 character limit for messages
56
+ max_length = 3900 # Leave some buffer
57
+ if len(message) > max_length:
58
+ message = message[:max_length] + "\n\n⚠️ *Message truncated due to length limit.*"
59
+
60
+ return message
61
+
62
+ def get_accessible_channels(client):
63
+ """Get channels where the bot can actually post messages."""
64
+ print("🔍 Finding accessible channels...")
65
+ accessible_channels = []
66
+
67
+ try:
68
+ # Get all public channels where the bot is a member
69
+ response = client.conversations_list(types="public_channel", limit=1000)
70
+ all_channels = response.get("channels", [])
71
+
72
+ print(f"Found {len(all_channels)} public channels. Testing access...")
73
+
74
+ for channel in all_channels:
75
+ channel_id = channel["id"]
76
+ channel_name = channel["name"]
77
+
78
+ # Check if bot is a member
79
+ try:
80
+ info_response = client.conversations_info(channel=channel_id)
81
+ channel_info = info_response["channel"]
82
+ is_member = channel_info.get("is_member", False)
83
+
84
+ if is_member:
85
+ print(f" ✅ Bot is member of #{channel_name}")
86
+ accessible_channels.append(channel)
87
+
88
+ except SlackApiError as e:
89
+ if e.response["error"] != "channel_not_found":
90
+ print(f" ❌ Error accessing #{channel_name}: {e.response['error']}")
91
+
92
+ except SlackApiError as e:
93
+ print(f"❌ Error getting public channels: {e.response['error']}")
94
+
95
+ print(f"Found {len(accessible_channels)} accessible channels")
96
+ return accessible_channels
97
+
98
+ def upload_video_file(client, channel_id, video_path):
99
+ """Upload video file to Slack channel using the new upload API."""
100
+ try:
101
+ if os.path.exists(video_path):
102
+ print(f"📹 Uploading video: {os.path.basename(video_path)}")
103
+
104
+ # Get file size
105
+ file_size = os.path.getsize(video_path)
106
+ filename = os.path.basename(video_path)
107
+
108
+ # Step 1: Get upload URL
109
+ upload_response = client.files_getUploadURLExternal(
110
+ filename=filename,
111
+ length=file_size
112
+ )
113
+
114
+ upload_url = upload_response["upload_url"]
115
+ file_id = upload_response["file_id"]
116
+
117
+ # Step 2: Upload file to the URL
118
+ import requests
119
+ with open(video_path, 'rb') as file_data:
120
+ upload_result = requests.post(upload_url, files={"file": file_data})
121
+
122
+ if upload_result.status_code != 200:
123
+ print(f"❌ Error uploading file data: HTTP {upload_result.status_code}")
124
+ return False
125
+
126
+ # Step 3: Complete the upload
127
+ complete_response = client.files_completeUploadExternal(
128
+ files=[{
129
+ "id": file_id,
130
+ "title": "SP500 Test Final Video"
131
+ }],
132
+ channel_id=channel_id,
133
+ initial_comment="📹 UI Test Video Results"
134
+ )
135
+
136
+ print(f"✅ Video uploaded successfully")
137
+ return True
138
+ else:
139
+ print(f"⚠️ Video file not found: {video_path}")
140
+ return False
141
+ except SlackApiError as e:
142
+ print(f"❌ Error uploading video: {e.response['error']}")
143
+ return False
144
+ except Exception as e:
145
+ print(f"❌ Error uploading video: {str(e)}")
146
+ return False
147
+
148
+ def post_test_results(client, channel_id, channel_name, message, video_path=None):
149
+ """Post test results message to a specific channel with optional video upload."""
150
+ try:
151
+ # First, upload the video if provided and exists
152
+ if video_path and os.path.exists(video_path):
153
+ upload_video_file(client, channel_id, video_path)
154
+ time.sleep(2) # Wait a bit between video upload and message post
155
+
156
+ response = client.chat_postMessage(
157
+ channel=channel_id,
158
+ text=message,
159
+ mrkdwn=True # Enable Slack markdown formatting
160
+ )
161
+ print(f"✅ Test results posted successfully to #{channel_name}")
162
+ return True
163
+ except SlackApiError as e:
164
+ print(f"❌ Error posting to #{channel_name}: {e.response['error']}")
165
+ return False
166
+
167
+ def main():
168
+ """Main function to post test results to Slack channels."""
169
+
170
+ # Check if bot token is set
171
+ bot_token = os.environ.get("SLACK_BOT_TOKEN")
172
+ if not bot_token:
173
+ print("❌ Error: SLACK_BOT_TOKEN environment variable not set!")
174
+ print("This script requires a Slack bot token to function.")
175
+ sys.exit(1)
176
+
177
+ # Initialize the Slack client
178
+ client = WebClient(token=bot_token)
179
+
180
+ # Test the connection
181
+ try:
182
+ auth_response = client.auth_test()
183
+ bot_name = auth_response["user"]
184
+ bot_id = auth_response["user_id"]
185
+ team_name = auth_response.get("team", "Unknown Team")
186
+ print(f"🤖 Connected as bot: {bot_name} (ID: {bot_id}) in team: {team_name}")
187
+
188
+ except SlackApiError as e:
189
+ print(f"❌ Error connecting to Slack: {e.response['error']}")
190
+ sys.exit(1)
191
+
192
+ # Get PR information
193
+ pr_number, pr_url, repo_name = get_pr_info()
194
+ print(f"📋 PR Info - Number: {pr_number}, Repository: {repo_name}")
195
+ if pr_url:
196
+ print(f"🔗 PR URL: {pr_url}")
197
+
198
+ # Get test results content
199
+ print("📖 Reading test results...")
200
+ test_content = get_test_results_content()
201
+
202
+ # Set video file path
203
+ video_path = os.path.join(os.path.dirname(__file__), "screenshots", "sp500_test_final.mp4")
204
+ print(f"📹 Video file path: {video_path}")
205
+
206
+ # Check if video file exists
207
+ if os.path.exists(video_path):
208
+ print(f"✅ Video file found: {os.path.basename(video_path)}")
209
+ else:
210
+ print(f"⚠️ Video file not found at: {video_path}")
211
+ video_path = None
212
+
213
+ # Format message for Slack
214
+ slack_message = format_slack_message(pr_number, pr_url, repo_name, test_content)
215
+
216
+ # Get channels the bot can access
217
+ bot_channels = get_accessible_channels(client)
218
+
219
+ if not bot_channels:
220
+ print("❌ Bot is not a member of any accessible channels!")
221
+ print("Make sure to invite the bot to at least one channel.")
222
+ sys.exit(1)
223
+
224
+ print(f"📢 Found {len(bot_channels)} channels to post to:")
225
+ for channel in bot_channels:
226
+ print(f" - #{channel['name']}")
227
+
228
+ # Post to each accessible channel
229
+ print(f"\n🚀 Posting test results...")
230
+ success_count = 0
231
+
232
+ for channel in bot_channels:
233
+ print(f"\n📤 Posting to #{channel['name']}...")
234
+ if post_test_results(client, channel["id"], channel["name"], slack_message, video_path):
235
+ success_count += 1
236
+ time.sleep(2) # Rate limiting - wait 2 seconds between posts to allow for video upload
237
+
238
+ print(f"\n✅ Completed! Successfully posted to {success_count}/{len(bot_channels)} channels.")
239
+
240
+ if success_count == 0:
241
+ print("⚠️ No messages were posted successfully.")
242
+ sys.exit(1)
243
+
244
+ if __name__ == "__main__":
245
+ main()