open-data-sci 0.2.0__tar.gz → 0.2.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.
Files changed (271) hide show
  1. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/PKG-INFO +25 -24
  2. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/adapter.py +3 -3
  3. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/app.py +6 -6
  4. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/controller.py +66 -64
  5. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/presenter.py +15 -12
  6. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/tools_display.py +4 -4
  7. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/widgets.py +122 -152
  8. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/agents/agents.py +4 -5
  9. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/agents/graphs.py +6 -4
  10. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/configs.py +5 -4
  11. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/models/aws.py +7 -4
  12. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/models/google.py +35 -21
  13. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/pyproject.toml +44 -31
  14. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/component/test_cli_controller.py +10 -10
  15. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/component/test_model_factories.py +1 -11
  16. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/component/test_tui_app.py +3 -3
  17. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/component/test_tui_widgets.py +103 -23
  18. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/conftest.py +3 -3
  19. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/test_app.py +2 -2
  20. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/test_controller.py +39 -37
  21. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/test_presenter.py +80 -77
  22. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/test_tools_display.py +4 -4
  23. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/test_widgets.py +188 -348
  24. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_utils/test_graph_utils.py +1 -0
  25. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/models/test_aws.py +1 -2
  26. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/tools/test_dataset_info.py +9 -12
  27. open_data_sci-0.2.1/uv.lock +3887 -0
  28. open_data_sci-0.2.0/uv.lock +0 -3558
  29. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/.env.example +0 -0
  30. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/.gitignore +0 -0
  31. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/LICENSE +0 -0
  32. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/Makefile +0 -0
  33. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/README.md +0 -0
  34. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/dev/scripts/test_pypi_install.sh +0 -0
  35. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/dev/scripts/test_pypi_publish.sh +0 -0
  36. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/api/agent.md +0 -0
  37. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/api/config.md +0 -0
  38. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/api/index.md +0 -0
  39. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/api/memory.md +0 -0
  40. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/api/open_data_sci.md +0 -0
  41. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/api/session.md +0 -0
  42. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/api/session_manager.md +0 -0
  43. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/api/skills.md +0 -0
  44. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/api/types.md +0 -0
  45. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/api/workbench.md +0 -0
  46. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/getting-started.md +0 -0
  47. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/index.md +0 -0
  48. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/docs/requirements.txt +0 -0
  49. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/README.md +0 -0
  50. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/configs/config_anthropic.yaml +0 -0
  51. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/configs/config_azure.yaml +0 -0
  52. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/configs/config_bedrock.yaml +0 -0
  53. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/configs/config_gemini.yaml +0 -0
  54. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/configs/config_ollama.yaml +0 -0
  55. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/configs/config_openai.yaml +0 -0
  56. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/configs/config_openai_compatible_server.yaml +0 -0
  57. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/configs/config_vertexai.yaml +0 -0
  58. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/notebooks/030_notebook_anthropic.ipynb +0 -0
  59. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/notebooks/031_notebook_openai_compatible_server.ipynb +0 -0
  60. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/notebooks/032_notebook_bedrock.ipynb +0 -0
  61. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/scripts/020_script_anthropic.py +0 -0
  62. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/scripts/021_script_openai_compatible_server.py +0 -0
  63. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/scripts/022_script_bedrock.py +0 -0
  64. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/tui/010_tui_anthropic.md +0 -0
  65. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/tui/011_tui_openai_compatible_server.md +0 -0
  66. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/examples/tui/012_tui_bedrock.md +0 -0
  67. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/mkdocs.yaml +0 -0
  68. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/__init__.py +0 -0
  69. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/__init__.py +0 -0
  70. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/commands.py +0 -0
  71. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/completion.py +0 -0
  72. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/file_refs.py +0 -0
  73. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/message_queue.py +0 -0
  74. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/models.py +0 -0
  75. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/service.py +0 -0
  76. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/session.py +0 -0
  77. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/styles.tcss +0 -0
  78. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_tui/theme.py +0 -0
  79. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_utils/__init__.py +0 -0
  80. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_utils/async_utils.py +0 -0
  81. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_utils/casing_utils.py +0 -0
  82. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_utils/data_formats.py +0 -0
  83. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_utils/datetime_utils.py +0 -0
  84. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_utils/graph_utils.py +0 -0
  85. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_utils/hash_utils.py +0 -0
  86. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_utils/message_utils.py +0 -0
  87. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_utils/mixins.py +0 -0
  88. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/_utils/streaming_utils.py +0 -0
  89. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/agents/__init__.py +0 -0
  90. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/agents/agents_factory.py +0 -0
  91. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/agents/chat_history.py +0 -0
  92. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/agents/nodes.py +0 -0
  93. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/agents/states.py +0 -0
  94. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/context/__init__.py +0 -0
  95. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/context/base.py +0 -0
  96. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/context/local.py +0 -0
  97. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/context/plans.py +0 -0
  98. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/human_inputs/__init__.py +0 -0
  99. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/human_inputs/human_approval.py +0 -0
  100. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/memory/__init__.py +0 -0
  101. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/memory/chat_memory.py +0 -0
  102. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/memory/messages.py +0 -0
  103. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/memory/turn_memory.py +0 -0
  104. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/models/__init__.py +0 -0
  105. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/models/anthropic.py +0 -0
  106. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/models/factory.py +0 -0
  107. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/models/local.py +0 -0
  108. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/models/microsoft.py +0 -0
  109. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/models/openai.py +0 -0
  110. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/models/providers.py +0 -0
  111. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/prompts/__init__.py +0 -0
  112. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/prompts/builders.py +0 -0
  113. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/prompts/caching.py +0 -0
  114. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/prompts/prompt_templates.py +0 -0
  115. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skill_domains/competitive_data_science/manifest.md +0 -0
  116. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skill_domains/data_science/manifest.md +0 -0
  117. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skill_domains/data_science_education/manifest.md +0 -0
  118. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skill_domains/deep_learning/manifest.md +0 -0
  119. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skill_domains/machine_learning/manifest.md +0 -0
  120. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skill_domains/quantitative_analysis/manifest.md +0 -0
  121. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/competitive_data_science/baseline.md +0 -0
  122. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/competitive_data_science/eda.md +0 -0
  123. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/competitive_data_science/ensembling.md +0 -0
  124. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/competitive_data_science/feature_engineering.md +0 -0
  125. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/competitive_data_science/final_submission.md +0 -0
  126. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/competitive_data_science/hyperparameter_tuning.md +0 -0
  127. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/competitive_data_science/model_development.md +0 -0
  128. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/competitive_data_science/phase_wiring.md +0 -0
  129. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/competitive_data_science/reconnaissance.md +0 -0
  130. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/competitive_data_science/validation.md +0 -0
  131. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science/causality_confounding.md +0 -0
  132. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science/communicating_findings.md +0 -0
  133. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science/data_quality_preparation.md +0 -0
  134. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science/exploratory_analysis.md +0 -0
  135. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science/framing_the_problem.md +0 -0
  136. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science/granularity_aggregation.md +0 -0
  137. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science/modeling_evaluation.md +0 -0
  138. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science/statistical_testing.md +0 -0
  139. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science_education/building_intuition.md +0 -0
  140. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science_education/calibrating_depth.md +0 -0
  141. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science_education/connecting_concepts.md +0 -0
  142. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science_education/diagnosing_understanding.md +0 -0
  143. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science_education/feedback_correction.md +0 -0
  144. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science_education/structuring_explanations.md +0 -0
  145. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/data_science_education/worked_examples_code.md +0 -0
  146. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/deep_learning/architecture_selection.md +0 -0
  147. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/deep_learning/evaluation.md +0 -0
  148. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/deep_learning/flax_nnx.md +0 -0
  149. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/deep_learning/hyperparameter_tuning.md +0 -0
  150. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/deep_learning/jax_fundamentals.md +0 -0
  151. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/deep_learning/library_stack.md +0 -0
  152. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/deep_learning/optax.md +0 -0
  153. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/deep_learning/regularisation_overfitting.md +0 -0
  154. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/deep_learning/sklearn_mlp.md +0 -0
  155. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/deep_learning/training_loop.md +0 -0
  156. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/deep_learning/when_to_use.md +0 -0
  157. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/machine_learning/class_imbalance.md +0 -0
  158. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/machine_learning/evaluation_diagnostics.md +0 -0
  159. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/machine_learning/feature_engineering_selection.md +0 -0
  160. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/machine_learning/hyperparameter_tuning.md +0 -0
  161. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/machine_learning/interpretability.md +0 -0
  162. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/machine_learning/model_selection_complexity.md +0 -0
  163. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/machine_learning/overfitting_regularisation.md +0 -0
  164. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/machine_learning/problem_framing.md +0 -0
  165. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/machine_learning/splitting_strategy.md +0 -0
  166. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/quantitative_analysis/backtesting_empirical_validation.md +0 -0
  167. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/quantitative_analysis/communicating_results.md +0 -0
  168. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/quantitative_analysis/mathematical_statistical_foundations.md +0 -0
  169. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/quantitative_analysis/optimisation.md +0 -0
  170. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/quantitative_analysis/problem_formulation.md +0 -0
  171. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/quantitative_analysis/risk_uncertainty_quantification.md +0 -0
  172. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/resources/skills/quantitative_analysis/time_series_signal_analysis.md +0 -0
  173. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/sandbox/__init__.py +0 -0
  174. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/sandbox/_runner.py +0 -0
  175. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/sandbox/base.py +0 -0
  176. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/sandbox/srt.py +0 -0
  177. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/session/__init__.py +0 -0
  178. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/session/session_manager.py +0 -0
  179. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/session/threads.py +0 -0
  180. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/skills/__init__.py +0 -0
  181. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/skills/base.py +0 -0
  182. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/skills/local.py +0 -0
  183. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/streaming/__init__.py +0 -0
  184. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/streaming/events.py +0 -0
  185. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/streaming/processors.py +0 -0
  186. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/__init__.py +0 -0
  187. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/base.py +0 -0
  188. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/coding.py +0 -0
  189. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/critic.py +0 -0
  190. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/dataset_info.py +0 -0
  191. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/factory.py +0 -0
  192. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/mcp.py +0 -0
  193. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/planning.py +0 -0
  194. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/skills.py +0 -0
  195. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/user_interaction.py +0 -0
  196. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/web.py +0 -0
  197. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/workers.py +0 -0
  198. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/tools/workspace.py +0 -0
  199. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/workspace/__init__.py +0 -0
  200. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/workspace/base.py +0 -0
  201. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/opendatasci/workspace/local.py +0 -0
  202. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/__init__.py +0 -0
  203. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/component/__init__.py +0 -0
  204. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/component/conftest.py +0 -0
  205. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/component/test_agent_integrations.py +0 -0
  206. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/component/test_lifecycle.py +0 -0
  207. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/component/test_real_streaming.py +0 -0
  208. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/component/test_sandbox_runner.py +0 -0
  209. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/component/test_service.py +0 -0
  210. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/component/test_streaming.py +0 -0
  211. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/__init__.py +0 -0
  212. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/__init__.py +0 -0
  213. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/test_commands.py +0 -0
  214. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/test_completion.py +0 -0
  215. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/test_file_refs.py +0 -0
  216. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/test_message_queue.py +0 -0
  217. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/test_service.py +0 -0
  218. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_tui/test_session.py +0 -0
  219. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_utils/__init__.py +0 -0
  220. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_utils/test_async_utils.py +0 -0
  221. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_utils/test_data_formats.py +0 -0
  222. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_utils/test_hash_utils.py +0 -0
  223. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/_utils/test_message_utils.py +0 -0
  224. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/agents/__init__.py +0 -0
  225. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/agents/test_agents.py +0 -0
  226. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/agents/test_agents_factory.py +0 -0
  227. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/agents/test_chat_messages.py +0 -0
  228. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/agents/test_graphs.py +0 -0
  229. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/agents/test_nodes.py +0 -0
  230. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/agents/test_states.py +0 -0
  231. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/conftest.py +0 -0
  232. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/context/__init__.py +0 -0
  233. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/context/test_local_context_store.py +0 -0
  234. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/context/test_local_work_context.py +0 -0
  235. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/human_inputs/__init__.py +0 -0
  236. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/human_inputs/test_human_approval.py +0 -0
  237. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/memory/__init__.py +0 -0
  238. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/memory/test_chat_memory.py +0 -0
  239. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/memory/test_turn_memory.py +0 -0
  240. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/models/__init__.py +0 -0
  241. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/models/test_anthropic.py +0 -0
  242. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/models/test_google.py +0 -0
  243. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/models/test_local.py +0 -0
  244. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/models/test_microsoft.py +0 -0
  245. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/models/test_openai.py +0 -0
  246. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/prompts/__init__.py +0 -0
  247. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/prompts/test_builders.py +0 -0
  248. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/prompts/test_caching.py +0 -0
  249. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/sandbox/__init__.py +0 -0
  250. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/sandbox/test_cli_validation.py +0 -0
  251. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/sandbox/test_exec_result.py +0 -0
  252. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/sandbox/test_runner.py +0 -0
  253. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/sandbox/test_srt.py +0 -0
  254. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/session/__init__.py +0 -0
  255. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/session/test_session_manager.py +0 -0
  256. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/skills/__init__.py +0 -0
  257. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/skills/test_local.py +0 -0
  258. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/streaming/__init__.py +0 -0
  259. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/streaming/test_processors.py +0 -0
  260. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/test_configs.py +0 -0
  261. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/tools/__init__.py +0 -0
  262. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/tools/test_coding.py +0 -0
  263. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/tools/test_critic.py +0 -0
  264. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/tools/test_factory.py +0 -0
  265. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/tools/test_mcp.py +0 -0
  266. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/tools/test_planning.py +0 -0
  267. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/tools/test_skills.py +0 -0
  268. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/tools/test_user_interaction.py +0 -0
  269. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/tools/test_web.py +0 -0
  270. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/tools/test_workers.py +0 -0
  271. {open_data_sci-0.2.0 → open_data_sci-0.2.1}/tests/unit/tools/test_workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: open-data-sci
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: AI agent for data science and machine learning
5
5
  Project-URL: Homepage, https://github.com/f4roukb/open-data-sci
6
6
  Project-URL: Repository, https://github.com/f4roukb/open-data-sci
@@ -219,69 +219,70 @@ Requires-Python: <3.13,>=3.12
219
219
  Requires-Dist: catboost<2.0.0,>=1.2.0
220
220
  Requires-Dist: category-encoders<3.0.0,>=2.6.0
221
221
  Requires-Dist: duckdb<2.0.0,>=1.0.0
222
- Requires-Dist: duckduckgo-search<7.0.0,>=6.0.0
222
+ Requires-Dist: duckduckgo-search<9.0.0,>=8.0.0
223
223
  Requires-Dist: httpx<1.0.0,>=0.27.0
224
224
  Requires-Dist: imbalanced-learn<1.0.0,>=0.12.0
225
- Requires-Dist: langchain-anthropic<1.0.0,>=0.2.0
226
- Requires-Dist: langchain-core<1.0.0,>=0.3.0
227
- Requires-Dist: langchain-openai<1.0.0,>=0.2.0
228
- Requires-Dist: langgraph<1.0.0,>=0.2.0
225
+ Requires-Dist: langchain-anthropic<2.0.0,>=1.0.0
226
+ Requires-Dist: langchain-core<2.0.0,>=1.0.0
227
+ Requires-Dist: langchain-openai<2.0.0,>=1.0.0
228
+ Requires-Dist: langgraph<2.0.0,>=1.0.0
229
229
  Requires-Dist: lightgbm<5.0.0,>=4.0.0
230
230
  Requires-Dist: lxml<7.0.0,>=6.1.0
231
231
  Requires-Dist: matplotlib<4.0.0,>=3.7.0
232
232
  Requires-Dist: networkx<4.0.0,>=3.0.0
233
- Requires-Dist: numpy<2.0.0,>=1.26.0
234
- Requires-Dist: optuna<4.0.0,>=3.6.0
235
- Requires-Dist: pandas[excel,feather,parquet]<3.0.0,>=2.0.0
236
- Requires-Dist: plotly<6.0.0,>=5.15.0
233
+ Requires-Dist: numpy<2.5.0,>=2.0.0
234
+ Requires-Dist: optuna<5.0.0,>=4.0.0
235
+ Requires-Dist: pandas[excel,feather,parquet]<4.0.0,>=3.0.0
236
+ Requires-Dist: plotly<7.0.0,>=6.0.0
237
237
  Requires-Dist: polars[calamine]<2.0.0,>=1.0.0
238
238
  Requires-Dist: prophet<2.0.0,>=1.1.0
239
239
  Requires-Dist: pydantic-settings<3.0.0,>=2.0.0
240
240
  Requires-Dist: pydantic<3.0.0,>=2.0.0
241
- Requires-Dist: pyod<3.0.0,>=2.0.0
241
+ Requires-Dist: pyod<4.0.0,>=3.0.0
242
242
  Requires-Dist: python-dotenv<2.0.0,>=1.0.0
243
243
  Requires-Dist: pyyaml<7.0,>=6.0
244
- Requires-Dist: rich<14.0.0,>=13.0.0
244
+ Requires-Dist: rich<16.0.0,>=15.0.0
245
245
  Requires-Dist: sandbox-runtime<1.0.0,>=0.2.0
246
246
  Requires-Dist: scikit-learn<2.0.0,>=1.5.0
247
247
  Requires-Dist: scipy<2.0.0,>=1.14.0
248
248
  Requires-Dist: seaborn<1.0.0,>=0.12.0
249
249
  Requires-Dist: shap<1.0.0,>=0.46.0
250
250
  Requires-Dist: statsmodels<1.0.0,>=0.14.0
251
- Requires-Dist: textual<0.48.0,>=0.47.0
251
+ Requires-Dist: textual<9.0.0,>=8.0.0
252
252
  Requires-Dist: umap-learn<1.0.0,>=0.5.0
253
- Requires-Dist: xgboost<3.0.0,>=2.0.0
253
+ Requires-Dist: xgboost<4.0.0,>=3.0.0
254
254
  Requires-Dist: xxhash<4.0.0,>=3.5.0
255
255
  Provides-Extra: aws
256
256
  Requires-Dist: boto3<2.0.0,>=1.34.0; extra == 'aws'
257
- Requires-Dist: langchain-aws<1.0.0,>=0.2.0; extra == 'aws'
257
+ Requires-Dist: langchain-aws<2.0.0,>=1.0.0; extra == 'aws'
258
258
  Provides-Extra: azure
259
259
  Requires-Dist: azure-identity<2.0.0,>=1.15.0; extra == 'azure'
260
260
  Provides-Extra: dev
261
- Requires-Dist: kaggle<2.0.0,>=1.6.0; extra == 'dev'
262
- Requires-Dist: mypy<2.0.0,>=1.13.0; extra == 'dev'
263
- Requires-Dist: pandas-stubs<3.0.0,>=2.0.0; extra == 'dev'
264
- Requires-Dist: pytest-asyncio<1.0.0,>=0.23.0; extra == 'dev'
261
+ Requires-Dist: kaggle<3.0.0,>=2.0.0; extra == 'dev'
262
+ Requires-Dist: mypy<3.0.0,>=2.0.0; extra == 'dev'
263
+ Requires-Dist: pandas-stubs<4.0.0,>=3.0.0; extra == 'dev'
264
+ Requires-Dist: pyright<2.0.0,>=1.1.390; extra == 'dev'
265
+ Requires-Dist: pytest-asyncio<2.0.0,>=0.23.0; extra == 'dev'
265
266
  Requires-Dist: pytest-cov<5.0.0,>=4.0.0; extra == 'dev'
266
267
  Requires-Dist: pytest-xdist<4.0.0,>=3.0.0; extra == 'dev'
267
- Requires-Dist: pytest<8.0.0,>=7.0.0; extra == 'dev'
268
+ Requires-Dist: pytest<10.0.0,>=9.0.0; extra == 'dev'
268
269
  Requires-Dist: ruff<1.0.0,>=0.8.0; extra == 'dev'
269
270
  Requires-Dist: types-openpyxl<4.0.0,>=3.1.0; extra == 'dev'
270
271
  Requires-Dist: vulture<3.0.0,>=2.0.0; extra == 'dev'
271
272
  Provides-Extra: docs
272
273
  Requires-Dist: mkdocs-material<10.0.0,>=9.5.0; extra == 'docs'
273
274
  Requires-Dist: mkdocs<2.0.0,>=1.6.0; extra == 'docs'
274
- Requires-Dist: mkdocstrings[python]<1.0.0,>=0.26.0; extra == 'docs'
275
+ Requires-Dist: mkdocstrings[python]<2.0.0,>=1.0.0; extra == 'docs'
275
276
  Provides-Extra: gcp
276
- Requires-Dist: langchain-google-vertexai<3.0.0,>=2.0.0; extra == 'gcp'
277
+ Requires-Dist: langchain-google-vertexai<4.0.0,>=3.0.0; extra == 'gcp'
277
278
  Provides-Extra: gemini
278
- Requires-Dist: langchain-google-genai<3.0.0,>=2.0.0; extra == 'gemini'
279
+ Requires-Dist: langchain-google-genai<5.0.0,>=4.0.0; extra == 'gemini'
279
280
  Provides-Extra: jax
280
281
  Requires-Dist: flax<1.0.0,>=0.8.0; extra == 'jax'
281
282
  Requires-Dist: jax[cpu]<1.0.0,>=0.4.0; extra == 'jax'
282
283
  Requires-Dist: optax<1.0.0,>=0.2.0; extra == 'jax'
283
284
  Provides-Extra: ollama
284
- Requires-Dist: langchain-ollama<1.0.0,>=0.2.0; extra == 'ollama'
285
+ Requires-Dist: langchain-ollama<2.0.0,>=1.0.0; extra == 'ollama'
285
286
  Description-Content-Type: text/markdown
286
287
 
287
288
  # OpenDataSci
@@ -11,11 +11,11 @@ from abc import ABC, abstractmethod
11
11
 
12
12
  class MessageHandle(ABC):
13
13
  @abstractmethod
14
- def append(self, chunk: str) -> None: ...
14
+ async def append(self, chunk: str) -> None: ...
15
15
  @abstractmethod
16
- def set_content(self, text: str) -> None: ...
16
+ async def set_content(self, text: str) -> None: ...
17
17
  @abstractmethod
18
- def finish(self) -> None: ...
18
+ async def finish(self) -> None: ...
19
19
 
20
20
 
21
21
  class EphemeralHandle(ABC):
@@ -33,6 +33,8 @@ from .widgets import (
33
33
  TurnStatusBar,
34
34
  )
35
35
 
36
+ logger = logging.getLogger(__name__)
37
+
36
38
 
37
39
  def _print_providers() -> None:
38
40
  table = Table(title=None, show_header=True, header_style="bold")
@@ -47,9 +49,7 @@ def _get_version() -> str:
47
49
  try:
48
50
  return importlib.metadata.version("open-data-sci")
49
51
  except importlib.metadata.PackageNotFoundError:
50
- logging.getLogger(__name__).warning(
51
- "open-data-sci package not found; falling back to hardcoded version '0.2.0'"
52
- )
52
+ logger.warning("open-data-sci package not found; falling back to hardcoded version '0.2.0'")
53
53
  return "0.2.0"
54
54
 
55
55
 
@@ -206,8 +206,8 @@ class OpenDataSciApp(App[None]):
206
206
  self.exit()
207
207
 
208
208
  @on(CommandApprovalPrompt.Decision)
209
- def on_approval_decision(self, event: CommandApprovalPrompt.Decision) -> None:
210
- resume_input = self._controller.resolve_approval(event.approved)
209
+ async def on_approval_decision(self, event: CommandApprovalPrompt.Decision) -> None:
210
+ resume_input = await self._controller.resolve_approval(event.approved)
211
211
  self.query_one("#user-input", Input).focus()
212
212
  self._run_agent(resume_input)
213
213
 
@@ -284,7 +284,7 @@ class OpenDataSciApp(App[None]):
284
284
  self._controller.hide_completion()
285
285
  self._controller.clear_paste_attachment()
286
286
  if self._controller.awaiting_choice:
287
- resume_input = self._controller.cancel_choice()
287
+ resume_input = await self._controller.cancel_choice()
288
288
  if resume_input is not None:
289
289
  self._run_agent(resume_input)
290
290
  elif not had_completion and not had_paste and self._controller.agent_running:
@@ -216,23 +216,23 @@ class CLIController:
216
216
  f"Check the path and try again.{hint}"
217
217
  )
218
218
  msg = ui.add_message("agent", "")
219
- msg.set_content(msg_text)
220
- msg.finish()
219
+ await msg.set_content(msg_text)
220
+ await msg.finish()
221
221
  except PermissionError:
222
222
  self._boot_failed = True
223
223
  msg = ui.add_message("agent", "")
224
- msg.set_content(f"❌ Permission denied: `{escape_markup(self._workspace_path)}`")
225
- msg.finish()
224
+ await msg.set_content(f"❌ Permission denied: `{escape_markup(self._workspace_path)}`")
225
+ await msg.finish()
226
226
  except ValueError as exc:
227
227
  self._boot_failed = True
228
228
  msg = ui.add_message("agent", "")
229
- msg.set_content(f"❌ Provider error: {exc}")
230
- msg.finish()
229
+ await msg.set_content(f"❌ Provider error: {exc}")
230
+ await msg.finish()
231
231
  except Exception as exc:
232
232
  self._boot_failed = True
233
233
  msg = ui.add_message("agent", "")
234
- msg.set_content(f"❌ Failed to load: {exc}")
235
- msg.finish()
234
+ await msg.set_content(f"❌ Failed to load: {exc}")
235
+ await msg.finish()
236
236
 
237
237
  @staticmethod
238
238
  def _did_you_mean(workspace_path: str) -> str:
@@ -317,7 +317,7 @@ class CLIController:
317
317
  self._exit_choice_mode()
318
318
  should_quit = await self._handle_slash(raw)
319
319
  return ("quit" if should_quit else ""), ""
320
- answer = self._handle_user_choice(raw)
320
+ answer = await self._handle_user_choice(raw)
321
321
  if answer is not None:
322
322
  return "run", answer
323
323
  return "", ""
@@ -339,7 +339,9 @@ class CLIController:
339
339
  clean_text, refs = _parse_file_refs(raw)
340
340
  valid_refs, missing_refs = _split_existing_file_refs(refs)
341
341
  for ref in missing_refs:
342
- self._ui.add_message("agent", f"⚠️ File not found: {escape_markup(ref._path)}").finish()
342
+ await self._ui.add_message(
343
+ "agent", f"⚠️ File not found: {escape_markup(ref._path)}"
344
+ ).finish()
343
345
 
344
346
  if refs and not clean_text and not valid_refs and attachment is None:
345
347
  return "", ""
@@ -375,14 +377,14 @@ class CLIController:
375
377
  """
376
378
  if self._service is None:
377
379
  if self._boot_failed:
378
- self._ui.add_message(
380
+ await self._ui.add_message(
379
381
  "agent",
380
382
  "❌ Startup failed, so queries can't run in this session. "
381
383
  "Fix the problem shown above and restart the app "
382
384
  "(type `/exit` to quit).",
383
385
  ).finish()
384
386
  else:
385
- self._ui.add_message(
387
+ await self._ui.add_message(
386
388
  "agent", "⚠️ Still loading — please wait a moment and try again."
387
389
  ).finish()
388
390
  return
@@ -413,14 +415,14 @@ class CLIController:
413
415
  if not isinstance(event, BaseAgentStreamEvent):
414
416
  logger.warning("astream() yielded unexpected type %r; skipping", type(event))
415
417
  continue
416
- self._dispatch_stream_event(event, presenter)
418
+ await self._dispatch_stream_event(event, presenter)
417
419
  if isinstance(event, (ResponseEvent, ErrorEvent)):
418
420
  break
419
421
  except Exception as exc:
420
- presenter.handle_exception(exc)
422
+ await presenter.handle_exception(exc)
421
423
  finally:
422
424
  self._agent_running = False
423
- presenter.cleanup()
425
+ await presenter.cleanup()
424
426
  if self._active_turn_status is not None:
425
427
  self._active_turn_status.stop()
426
428
  self._active_turn_status = None
@@ -428,18 +430,18 @@ class CLIController:
428
430
  self._ui.set_input_placeholder("Ask a question about your data…")
429
431
  self._ui.add_divider()
430
432
 
431
- def _dispatch_stream_event(
433
+ async def _dispatch_stream_event(
432
434
  self, event: BaseAgentStreamEvent, presenter: _TurnPresenter
433
435
  ) -> None:
434
436
  """Route a single stream event to the appropriate presenter handler."""
435
437
  if isinstance(event, ReasoningEvent):
436
438
  presenter.handle_reasoning(event)
437
439
  elif isinstance(event, TokenEvent):
438
- presenter.handle_token(event)
440
+ await presenter.handle_token(event)
439
441
  elif isinstance(event, ToolCommunicationEvent):
440
442
  presenter.handle_tool_communication(event)
441
443
  elif isinstance(event, ToolCallEvent):
442
- presenter.handle_tool_call(event)
444
+ await presenter.handle_tool_call(event)
443
445
  elif isinstance(event, WorkerDoneEvent):
444
446
  presenter.handle_worker_done(event)
445
447
  elif isinstance(event, SubagentEvent):
@@ -449,17 +451,17 @@ class CLIController:
449
451
  elif isinstance(event, UsageEvent):
450
452
  apply_usage_event(event, self._active_turn_status)
451
453
  elif isinstance(event, InputRequiredEvent):
452
- self._show_choice_prompt(event.content, list(event.choices))
454
+ await self._show_choice_prompt(event.content, list(event.choices))
453
455
  elif isinstance(event, ApprovalRequiredEvent):
454
456
  self._show_approval_prompt(event)
455
457
  elif isinstance(event, ResponseEvent):
456
458
  presenter.handle_response(event)
457
459
  elif isinstance(event, ErrorEvent):
458
- presenter.handle_error(event)
460
+ await presenter.handle_error(event)
459
461
 
460
462
  # ── Choice handling ───────────────────────────────────────────────────────
461
463
 
462
- def _show_choice_prompt(self, question: str, choices: list[str]) -> None:
464
+ async def _show_choice_prompt(self, question: str, choices: list[str]) -> None:
463
465
  labels = string.ascii_uppercase[: len(choices)]
464
466
  other_label = (
465
467
  string.ascii_uppercase[len(choices)]
@@ -484,7 +486,7 @@ class CLIController:
484
486
  lines.append(
485
487
  f" [dim {theme['text_secondary']}]Press Esc to cancel[/dim {theme['text_secondary']}]"
486
488
  )
487
- self._ui.add_message("question", "\n".join(lines)).finish()
489
+ await self._ui.add_message("question", "\n".join(lines)).finish()
488
490
  self._pending_choices = list(choices)
489
491
  self._other_choice_label = other_label
490
492
  self._awaiting_custom_choice_input = False
@@ -512,7 +514,7 @@ class CLIController:
512
514
  self._ui.set_input_placeholder("Ask a question about your data…")
513
515
  self._ui.remove_input_class("awaiting-choice")
514
516
 
515
- def cancel_choice(self) -> str | None:
517
+ async def cancel_choice(self) -> str | None:
516
518
  """Exit choice mode and return the resume input to send to the agent.
517
519
 
518
520
  Returns ``"cancel"`` when a choice was active (caller must pass this
@@ -521,10 +523,10 @@ class CLIController:
521
523
  if not self._awaiting_choice:
522
524
  return None
523
525
  self._exit_choice_mode()
524
- self._ui.add_message("agent", "Choice cancelled.").finish()
526
+ await self._ui.add_message("agent", "Choice cancelled.").finish()
525
527
  return "cancel"
526
528
 
527
- def _handle_user_choice(self, raw: str) -> str | None:
529
+ async def _handle_user_choice(self, raw: str) -> str | None:
528
530
  raw_stripped = raw.strip()
529
531
  upper = raw_stripped.upper()
530
532
  if (
@@ -534,7 +536,7 @@ class CLIController:
534
536
  ):
535
537
  self._awaiting_custom_choice_input = True
536
538
  self._other_choice_label = None
537
- self._ui.add_message("agent", "Type your answer and press Enter.").finish()
539
+ await self._ui.add_message("agent", "Type your answer and press Enter.").finish()
538
540
  self._ui.set_input_placeholder("Type your answer and press Enter…")
539
541
  return None
540
542
 
@@ -550,7 +552,7 @@ class CLIController:
550
552
  else raw_stripped
551
553
  )
552
554
 
553
- self._ui.add_message("user", escape_markup(raw)).finish()
555
+ await self._ui.add_message("user", escape_markup(raw)).finish()
554
556
  return answer
555
557
 
556
558
  # ── Approval handling ─────────────────────────────────────────────────────
@@ -564,7 +566,7 @@ class CLIController:
564
566
  self._awaiting_approval = True
565
567
  self._ui.set_input_placeholder("↑/↓ to select Yes or No, Enter to confirm, Esc to decline…")
566
568
 
567
- def resolve_approval(self, approved: bool) -> str:
569
+ async def resolve_approval(self, approved: bool) -> str:
568
570
  """Record the user's approval decision and return the resume input.
569
571
 
570
572
  The caller must pass the returned value to ``run_agent`` so the paused
@@ -572,7 +574,7 @@ class CLIController:
572
574
  """
573
575
  self._awaiting_approval = False
574
576
  self._ui.set_input_placeholder("Ask a question about your data…")
575
- self._ui.add_message("user", "Yes" if approved else "No").finish()
577
+ await self._ui.add_message("user", "Yes" if approved else "No").finish()
576
578
  return "yes" if approved else "no"
577
579
 
578
580
  # ── Slash command dispatch ────────────────────────────────────────────────
@@ -593,26 +595,26 @@ class CLIController:
593
595
  elif cmd == "/compact":
594
596
  await self.compact()
595
597
  elif cmd == "/ls-workspace":
596
- self.ls_workspace()
598
+ await self.ls_workspace()
597
599
  elif cmd == "/models":
598
- self.show_models()
600
+ await self.show_models()
599
601
  elif cmd == "/stop":
600
602
  await self.stop_agent()
601
603
  elif cmd == "/cancel-all-messages":
602
- self.cancel_pending_messages()
604
+ await self.cancel_pending_messages()
603
605
  elif cmd == "/cancel-message":
604
- self.cancel_last_pending_message()
606
+ await self.cancel_last_pending_message()
605
607
  elif cmd == "/help":
606
- self.show_help()
608
+ await self.show_help()
607
609
  elif cmd == "/themes":
608
- self.show_themes()
610
+ await self.show_themes()
609
611
  elif cmd == "/vars":
610
- self._ui.add_message(
612
+ await self._ui.add_message(
611
613
  "agent",
612
614
  "⚠️ `/vars` has been removed. Use `/help` to see available commands.",
613
615
  ).finish()
614
616
  else:
615
- self._ui.add_message(
617
+ await self._ui.add_message(
616
618
  "agent",
617
619
  f"⚠️ Unknown command: `{cmd}`\n\nType `/help` to see all available commands.",
618
620
  ).finish()
@@ -628,11 +630,11 @@ class CLIController:
628
630
  if self._service is not None:
629
631
  try:
630
632
  await self._service.reset_session()
631
- self._ui.add_message("agent", "✓ Session reset.").finish()
633
+ await self._ui.add_message("agent", "✓ Session reset.").finish()
632
634
  except Exception as exc:
633
- self._ui.add_message("agent", f"❌ Reset failed: {exc}").finish()
635
+ await self._ui.add_message("agent", f"❌ Reset failed: {exc}").finish()
634
636
  else:
635
- self._ui.add_message("agent", "Not loaded yet.").finish()
637
+ await self._ui.add_message("agent", "Not loaded yet.").finish()
636
638
 
637
639
  async def clear_conv(self) -> None:
638
640
  """Clear all conversation context (preserves session variables)."""
@@ -648,40 +650,40 @@ class CLIController:
648
650
  await self._service.clear_context()
649
651
  except Exception:
650
652
  logger.exception("Failed to clear service context")
651
- self._ui.add_message("agent", "✓ Context cleared.").finish()
653
+ await self._ui.add_message("agent", "✓ Context cleared.").finish()
652
654
 
653
655
  async def compact(self) -> None:
654
656
  """Summarize the conversation and replace it with a compact context preamble."""
655
657
  if self._service is None:
656
- self._ui.add_message("agent", "Not loaded yet.").finish()
658
+ await self._ui.add_message("agent", "Not loaded yet.").finish()
657
659
  return
658
660
  status = self._ui.add_message("agent", "Compacting conversation…")
659
- status.set_content("Compacting conversation…")
661
+ await status.set_content("Compacting conversation…")
660
662
  compact_timer: TurnStatusHandle | None = self._ui.add_turn_status_bar()
661
663
  try:
662
664
  await self._service.compact_chat_history()
663
665
  except Exception as exc:
664
- status.set_content(f"❌ Compact failed: {exc}")
666
+ await status.set_content(f"❌ Compact failed: {exc}")
665
667
  if compact_timer is not None:
666
668
  compact_timer.stop()
667
- status.finish()
669
+ await status.finish()
668
670
  return
669
671
  try:
670
672
  self._ui.clear_messages()
671
673
  compact_timer = None # removed from DOM by clear_messages()
672
- self._ui.add_message(
674
+ await self._ui.add_message(
673
675
  "agent",
674
676
  "**✓ Compaction done.** You may continue the conversation.",
675
677
  ).finish()
676
678
  finally:
677
- status.finish()
679
+ await status.finish()
678
680
  if compact_timer is not None:
679
681
  compact_timer.stop()
680
682
 
681
- def show_models(self) -> None:
683
+ async def show_models(self) -> None:
682
684
  """Display the primary and secondary model in use."""
683
685
  cfg = self._cfg or self._base_config
684
- self._ui.add_message(
686
+ await self._ui.add_message(
685
687
  "agent",
686
688
  format_models_message(
687
689
  cfg.provider,
@@ -691,13 +693,13 @@ class CLIController:
691
693
  ),
692
694
  ).finish()
693
695
 
694
- def show_help(self) -> None:
696
+ async def show_help(self) -> None:
695
697
  """Display all available slash commands with descriptions."""
696
- self._ui.add_message("agent", format_help_message()).finish()
698
+ await self._ui.add_message("agent", format_help_message()).finish()
697
699
 
698
- def show_themes(self) -> None:
700
+ async def show_themes(self) -> None:
699
701
  """Display the list of available colour themes and mark the active one."""
700
- self._ui.add_message(
702
+ await self._ui.add_message(
701
703
  "agent",
702
704
  format_themes_message(_theme.active_name, _theme.THEME_DESCRIPTIONS),
703
705
  ).finish()
@@ -705,34 +707,34 @@ class CLIController:
705
707
  async def stop_agent(self) -> None:
706
708
  """Stop the currently running agent turn."""
707
709
  if not self._agent_running:
708
- self._ui.add_message("agent", "No agent is currently running.").finish()
710
+ await self._ui.add_message("agent", "No agent is currently running.").finish()
709
711
  return
710
712
  self._ui.stop_agent()
711
713
  if self._service is not None:
712
714
  await self._service.rewind_turn()
713
- self._ui.add_message("agent", "⏹ Agent stopped. You can continue from here.").finish()
715
+ await self._ui.add_message("agent", "⏹ Agent stopped. You can continue from here.").finish()
714
716
 
715
- def cancel_pending_messages(self) -> None:
717
+ async def cancel_pending_messages(self) -> None:
716
718
  """Discard every message currently queued behind a running agent turn."""
717
719
  removed = self._pending_queue.cancel_all()
718
720
  for message in removed:
719
721
  self._discard_pending_handle(message.id)
720
722
  if removed:
721
723
  count = len(removed)
722
- self._ui.add_message(
724
+ await self._ui.add_message(
723
725
  "agent", f"✓ Cancelled {count} pending message{'s' if count != 1 else ''}."
724
726
  ).finish()
725
727
  else:
726
- self._ui.add_message("agent", "No pending messages to cancel.").finish()
728
+ await self._ui.add_message("agent", "No pending messages to cancel.").finish()
727
729
 
728
- def cancel_last_pending_message(self) -> None:
730
+ async def cancel_last_pending_message(self) -> None:
729
731
  """Discard only the most recently queued message."""
730
732
  message = self._pending_queue.cancel_last()
731
733
  if message is None:
732
- self._ui.add_message("agent", "No pending messages to cancel.").finish()
734
+ await self._ui.add_message("agent", "No pending messages to cancel.").finish()
733
735
  return
734
736
  self._discard_pending_handle(message.id)
735
- self._ui.add_message("agent", "✓ Cancelled last pending message.").finish()
737
+ await self._ui.add_message("agent", "✓ Cancelled last pending message.").finish()
736
738
 
737
739
  def _discard_pending_handle(self, message_id: int) -> None:
738
740
  handle = self._pending_handles.pop(message_id, None)
@@ -744,13 +746,13 @@ class CLIController:
744
746
  for message in self._pending_queue.cancel_all():
745
747
  self._discard_pending_handle(message.id)
746
748
 
747
- def ls_workspace(self) -> None:
749
+ async def ls_workspace(self) -> None:
748
750
  if self._service is None:
749
- self._ui.add_message("agent", "_Not loaded yet._").finish()
751
+ await self._ui.add_message("agent", "_Not loaded yet._").finish()
750
752
  return
751
753
  try:
752
754
  files = self._service.get_workspace_files()
753
755
  except Exception as exc:
754
- self._ui.add_message("agent", f"❌ {exc}").finish()
756
+ await self._ui.add_message("agent", f"❌ {exc}").finish()
755
757
  return
756
758
  self._ui.show_workspace_panel(files)
@@ -53,8 +53,11 @@ def apply_usage_event(event: UsageEvent, turn_status: TurnStatusHandle | None) -
53
53
  class _TurnPresenter:
54
54
  """Manages ephemeral UI state (bubbles, tool blocks, thinking) for one turn.
55
55
 
56
- All methods are synchronous; awaiting happens inside ``MessageBubble``
57
- and ``ToolCallBlock`` via Textual's own async machinery.
56
+ Handlers that touch a ``MessageHandle`` (``handle_token``,
57
+ ``handle_tool_call``, ``handle_error``, ``handle_exception``,
58
+ ``cleanup``) are async, since ``MessageHandle.append/set_content/finish``
59
+ are async (they await Textual's ``MarkdownStream``). The rest stay
60
+ synchronous.
58
61
  """
59
62
 
60
63
  def __init__(self, ui: UIAdapter) -> None:
@@ -118,11 +121,11 @@ class _TurnPresenter:
118
121
  self._thinking_start = time.monotonic()
119
122
  self._had_reasoning = True
120
123
 
121
- def handle_token(self, event: TokenEvent) -> None:
124
+ async def handle_token(self, event: TokenEvent) -> None:
122
125
  self._finish_thinking()
123
126
  if self._agent_msg is None:
124
127
  self._agent_msg = self._ui.add_message("agent", "")
125
- self._agent_msg.append(event.content)
128
+ await self._agent_msg.append(event.content)
126
129
 
127
130
  def handle_tool_communication(self, event: ToolCommunicationEvent) -> None:
128
131
  tool_display = REGISTRY.get(event.tool_name) if event.tool_name else None
@@ -146,7 +149,7 @@ class _TurnPresenter:
146
149
  self._ephemerals.append(block)
147
150
  self._ephemerals_by_id[tc_id] = block
148
151
 
149
- def handle_tool_call(self, event: ToolCallEvent) -> None:
152
+ async def handle_tool_call(self, event: ToolCallEvent) -> None:
150
153
  tool_call_id = event.tool_call_id or ""
151
154
  existing = self._pending_ephemerals.pop(tool_call_id, None) if tool_call_id else None
152
155
  tool_display = REGISTRY.get(str(event.tool))
@@ -173,7 +176,7 @@ class _TurnPresenter:
173
176
  self._finish_thinking()
174
177
  has_narration = self._agent_msg is not None
175
178
  if self._agent_msg is not None:
176
- self._agent_msg.finish()
179
+ await self._agent_msg.finish()
177
180
  self._agent_msg = None
178
181
 
179
182
  buffered_comm = self._comm_buffers.pop(tool_call_id, "")
@@ -255,24 +258,24 @@ class _TurnPresenter:
255
258
  if self._agent_msg is None and event.content:
256
259
  self._agent_msg = self._ui.add_message("agent", event.content)
257
260
 
258
- def handle_error(self, event: ErrorEvent) -> None:
261
+ async def handle_error(self, event: ErrorEvent) -> None:
259
262
  self._dismiss_thinking_block()
260
263
  if self._agent_msg is None:
261
264
  self._agent_msg = self._ui.add_message("agent", "")
262
- self._agent_msg.append(f"\n\n❌ {event.content}")
265
+ await self._agent_msg.append(f"\n\n❌ {event.content}")
263
266
 
264
- def handle_exception(self, exc: Exception) -> None:
267
+ async def handle_exception(self, exc: Exception) -> None:
265
268
  self._dismiss_thinking_block()
266
269
  if self._agent_msg is None:
267
270
  self._agent_msg = self._ui.add_message("agent", "")
268
- self._agent_msg.set_content(f"❌ **Error:** {exc}")
271
+ await self._agent_msg.set_content(f"❌ **Error:** {exc}")
269
272
 
270
273
  # ── Cleanup ───────────────────────────────────────────────────────────────
271
274
 
272
- def cleanup(self) -> None:
275
+ async def cleanup(self) -> None:
273
276
  """Finalise all open UI elements (called from the run_agent finally block)."""
274
277
  self._finish_thinking()
275
278
  for e in self._ephemerals:
276
279
  e.set_done()
277
280
  if self._agent_msg is not None:
278
- self._agent_msg.finish()
281
+ await self._agent_msg.finish()
@@ -58,7 +58,7 @@ def register(tool_name: str, display: ToolDisplay) -> None:
58
58
  # from opendatasci.tools.factory (which creates a circular dependency).
59
59
 
60
60
  register("execute_python_code", ToolDisplay(label="Code", icon="🐍", summary_arg="summary"))
61
- register("execute_cli_command", ToolDisplay(label="Command", icon="⌨️", summary_arg="summary"))
61
+ register("execute_cli_command", ToolDisplay(label="Command", icon="💻", summary_arg="summary"))
62
62
  register(
63
63
  "list_python_libs",
64
64
  ToolDisplay(label="Checking available libraries", icon="📦", summary_arg="summary"),
@@ -67,13 +67,13 @@ register(
67
67
  "enter_plan_mode",
68
68
  ToolDisplay(label="Planning the next steps", icon="🎯", summary_arg="summary"),
69
69
  )
70
- register("exit_plan_mode", ToolDisplay(label="Planning complete", icon="", summary_arg="summary"))
70
+ register("exit_plan_mode", ToolDisplay(label="Planning complete", icon="🏁", summary_arg="summary"))
71
71
  register("load_skill", ToolDisplay(label="Loading skill", icon="🧠", summary_arg="summary"))
72
72
  register(
73
73
  "list_skills",
74
74
  ToolDisplay(label="Checking available skills", icon="🧭", summary_arg="summary"),
75
75
  )
76
- register("spawn_workers", ToolDisplay(label="Spawning workers", icon="⚙️", summary_arg="summary"))
76
+ register("spawn_workers", ToolDisplay(label="Spawning workers", icon="👥", summary_arg="summary"))
77
77
  register(
78
78
  "read_dataset_info",
79
79
  ToolDisplay(
@@ -116,5 +116,5 @@ register(
116
116
  )
117
117
  register(
118
118
  "verify_python_code",
119
- ToolDisplay(label="Reviewing code", icon="🔎", summary_arg="summary"),
119
+ ToolDisplay(label="Reviewing code", icon="🧪", summary_arg="summary"),
120
120
  )