kash-shell 0.3.35__tar.gz → 0.3.36__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 (336) hide show
  1. {kash_shell-0.3.35 → kash_shell-0.3.36}/.copier-answers.yml +1 -1
  2. {kash_shell-0.3.35 → kash_shell-0.3.36}/.cursor/rules/general.mdc +11 -11
  3. {kash_shell-0.3.35 → kash_shell-0.3.36}/.cursor/rules/python.mdc +23 -8
  4. {kash_shell-0.3.35 → kash_shell-0.3.36}/.github/workflows/ci.yml +1 -1
  5. {kash_shell-0.3.35 → kash_shell-0.3.36}/.github/workflows/publish.yml +1 -1
  6. {kash_shell-0.3.35 → kash_shell-0.3.36}/PKG-INFO +1 -1
  7. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/llm_transforms.py +4 -0
  8. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/file_storage/file_store.py +4 -0
  9. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/llm_utils/llm_completion.py +115 -19
  10. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/llm_utils/llms.py +8 -7
  11. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/actions_model.py +7 -3
  12. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/items_model.py +8 -1
  13. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/params_model.py +4 -4
  14. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/youtube_webpage.html.jinja +3 -2
  15. kash_shell-0.3.36/uv.lock +3575 -0
  16. kash_shell-0.3.35/uv.lock +0 -3120
  17. {kash_shell-0.3.35 → kash_shell-0.3.36}/.env.template +0 -0
  18. {kash_shell-0.3.35 → kash_shell-0.3.36}/.gitignore +0 -0
  19. {kash_shell-0.3.35 → kash_shell-0.3.36}/LICENSE +0 -0
  20. {kash_shell-0.3.35 → kash_shell-0.3.36}/Makefile +0 -0
  21. {kash_shell-0.3.35 → kash_shell-0.3.36}/README.md +0 -0
  22. {kash_shell-0.3.35 → kash_shell-0.3.36}/development.md +0 -0
  23. {kash_shell-0.3.35 → kash_shell-0.3.36}/devtools/generate_readme.xsh +0 -0
  24. {kash_shell-0.3.35 → kash_shell-0.3.36}/devtools/lint.py +0 -0
  25. {kash_shell-0.3.35 → kash_shell-0.3.36}/devtools/profile_main.py +0 -0
  26. {kash_shell-0.3.35 → kash_shell-0.3.36}/installation.md +0 -0
  27. {kash_shell-0.3.35 → kash_shell-0.3.36}/publishing.md +0 -0
  28. {kash_shell-0.3.35 → kash_shell-0.3.36}/pyproject.toml +0 -0
  29. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/__init__.py +0 -0
  30. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/__main__.py +0 -0
  31. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/__init__.py +0 -0
  32. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/assistant_chat.py +0 -0
  33. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/chat.py +0 -0
  34. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/combine_docs.py +0 -0
  35. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/concat_docs.py +0 -0
  36. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/format_markdown_template.py +0 -0
  37. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/markdownify_html.py +0 -0
  38. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/minify_html.py +0 -0
  39. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/readability.py +0 -0
  40. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/render_as_html.py +0 -0
  41. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/save_sidematter_meta.py +0 -0
  42. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/show_webpage.py +0 -0
  43. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/strip_html.py +0 -0
  44. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/summarize_as_bullets.py +0 -0
  45. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/tabbed_webpage_config.py +0 -0
  46. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/tabbed_webpage_generate.py +0 -0
  47. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/core/zip_sidematter.py +0 -0
  48. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/meta/write_instructions.py +0 -0
  49. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/actions/meta/write_new_action.py +0 -0
  50. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/__init__.py +0 -0
  51. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/base/basic_file_commands.py +0 -0
  52. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/base/browser_commands.py +0 -0
  53. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/base/debug_commands.py +0 -0
  54. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/base/diff_commands.py +0 -0
  55. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/base/files_command.py +0 -0
  56. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/base/general_commands.py +0 -0
  57. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/base/logs_commands.py +0 -0
  58. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/base/model_commands.py +0 -0
  59. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/base/reformat_command.py +0 -0
  60. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/base/search_command.py +0 -0
  61. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/base/show_command.py +0 -0
  62. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/extras/parse_uv_lock.py +0 -0
  63. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/extras/utils_commands.py +0 -0
  64. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/help/assistant_commands.py +0 -0
  65. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/help/doc_commands.py +0 -0
  66. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/help/help_commands.py +0 -0
  67. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/help/logo.py +0 -0
  68. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/help/welcome.py +0 -0
  69. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/workspace/selection_commands.py +0 -0
  70. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/commands/workspace/workspace_commands.py +0 -0
  71. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/__init__.py +0 -0
  72. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/capture_output.py +0 -0
  73. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/colors.py +0 -0
  74. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/env_settings.py +0 -0
  75. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/init.py +0 -0
  76. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/lazy_imports.py +0 -0
  77. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/logger.py +0 -0
  78. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/logger_basic.py +0 -0
  79. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/logo.txt +0 -0
  80. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/server_config.py +0 -0
  81. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/settings.py +0 -0
  82. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/setup.py +0 -0
  83. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/suppress_warnings.py +0 -0
  84. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/text_styles.py +0 -0
  85. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/unified_live.py +0 -0
  86. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/config/warm_slow_imports.py +0 -0
  87. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/__init__.py +0 -0
  88. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/all_docs.py +0 -0
  89. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/load_actions_info.py +0 -0
  90. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/load_api_docs.py +0 -0
  91. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/load_help_topics.py +0 -0
  92. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/load_source_code.py +0 -0
  93. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/api_docs_template.md +0 -0
  94. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/assistant_instructions_template.md +0 -0
  95. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/readme_template.md +0 -0
  96. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/topics/a1_what_is_kash.md +0 -0
  97. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/topics/a2_installation.md +0 -0
  98. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/topics/a3_getting_started.md +0 -0
  99. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/topics/a4_elements.md +0 -0
  100. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/topics/a5_tips_for_use_with_other_tools.md +0 -0
  101. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/topics/b0_philosophy_of_kash.md +0 -0
  102. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/topics/b1_kash_overview.md +0 -0
  103. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/topics/b2_workspace_and_file_formats.md +0 -0
  104. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/topics/b3_modern_shell_tool_recommendations.md +0 -0
  105. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/topics/b4_faq.md +0 -0
  106. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/warning.md +0 -0
  107. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs/markdown/welcome.md +0 -0
  108. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs_base/docs_base.py +0 -0
  109. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs_base/load_custom_command_info.py +0 -0
  110. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs_base/load_faqs.py +0 -0
  111. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs_base/load_recipe_snippets.py +0 -0
  112. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs_base/recipes/general_system_commands.sh +0 -0
  113. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs_base/recipes/python_dev_commands.sh +0 -0
  114. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/docs_base/recipes/tldr_standard_commands.sh +0 -0
  115. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/embeddings/cosine.py +0 -0
  116. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/embeddings/embeddings.py +0 -0
  117. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/embeddings/text_similarity.py +0 -0
  118. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/__init__.py +0 -0
  119. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/action_decorators.py +0 -0
  120. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/action_exec.py +0 -0
  121. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/action_registry.py +0 -0
  122. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/combiners.py +0 -0
  123. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/command_exec.py +0 -0
  124. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/command_registry.py +0 -0
  125. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/fetch_url_items.py +0 -0
  126. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/history.py +0 -0
  127. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/importing.py +0 -0
  128. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/precondition_checks.py +0 -0
  129. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/precondition_registry.py +0 -0
  130. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/preconditions.py +0 -0
  131. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/resolve_args.py +0 -0
  132. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/runtime_settings.py +0 -0
  133. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec/shell_callable_action.py +0 -0
  134. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec_model/__init__.py +0 -0
  135. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec_model/args_model.py +0 -0
  136. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec_model/commands_model.py +0 -0
  137. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec_model/script_model.py +0 -0
  138. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/exec_model/shell_model.py +0 -0
  139. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/file_storage/__init__.py +0 -0
  140. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/file_storage/item_file_format.py +0 -0
  141. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/file_storage/item_id_index.py +0 -0
  142. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/file_storage/metadata_dirs.py +0 -0
  143. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/file_storage/persisted_yaml.py +0 -0
  144. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/file_storage/store_cache_warmer.py +0 -0
  145. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/file_storage/store_filenames.py +0 -0
  146. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/help/__init__.py +0 -0
  147. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/help/assistant.py +0 -0
  148. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/help/assistant_instructions.py +0 -0
  149. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/help/assistant_output.py +0 -0
  150. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/help/function_param_info.py +0 -0
  151. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/help/help_embeddings.py +0 -0
  152. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/help/help_lookups.py +0 -0
  153. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/help/help_pages.py +0 -0
  154. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/help/help_printing.py +0 -0
  155. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/help/help_types.py +0 -0
  156. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/help/recommended_commands.py +0 -0
  157. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/help/tldr_help.py +0 -0
  158. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/llm_utils/__init__.py +0 -0
  159. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/llm_utils/clean_headings.py +0 -0
  160. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/llm_utils/custom_sliding_transforms.py +0 -0
  161. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/llm_utils/fuzzy_parsing.py +0 -0
  162. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/llm_utils/init_litellm.py +0 -0
  163. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/llm_utils/llm_api_keys.py +0 -0
  164. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/llm_utils/llm_messages.py +0 -0
  165. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/llm_utils/llm_names.py +0 -0
  166. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/local_server/__init__.py +0 -0
  167. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/local_server/local_server.py +0 -0
  168. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/local_server/local_server_commands.py +0 -0
  169. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/local_server/local_server_routes.py +0 -0
  170. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/local_server/local_url_formatters.py +0 -0
  171. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/local_server/port_tools.py +0 -0
  172. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/local_server/rich_html_template.py +0 -0
  173. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/mcp/__init__.py +0 -0
  174. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/mcp/mcp_cli.py +0 -0
  175. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/mcp/mcp_main.py +0 -0
  176. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/mcp/mcp_server_commands.py +0 -0
  177. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/mcp/mcp_server_routes.py +0 -0
  178. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/mcp/mcp_server_sse.py +0 -0
  179. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/mcp/mcp_server_stdio.py +0 -0
  180. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/media_base/__init__.py +0 -0
  181. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/media_base/audio_processing.py +0 -0
  182. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/media_base/media_cache.py +0 -0
  183. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/media_base/media_services.py +0 -0
  184. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/media_base/media_tools.py +0 -0
  185. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/media_base/services/local_file_media.py +0 -0
  186. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/media_base/timestamp_citations.py +0 -0
  187. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/media_base/transcription_deepgram.py +0 -0
  188. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/media_base/transcription_format.py +0 -0
  189. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/media_base/transcription_whisper.py +0 -0
  190. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/__init__.py +0 -0
  191. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/assistant_response_model.py +0 -0
  192. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/compound_actions_model.py +0 -0
  193. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/concept_model.py +0 -0
  194. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/exec_model.py +0 -0
  195. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/graph_model.py +0 -0
  196. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/language_list.py +0 -0
  197. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/llm_actions_model.py +0 -0
  198. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/media_model.py +0 -0
  199. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/operations_model.py +0 -0
  200. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/paths_model.py +0 -0
  201. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/model/preconditions_model.py +0 -0
  202. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/__init__.py +0 -0
  203. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/completions/completion_scoring.py +0 -0
  204. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/completions/completion_types.py +0 -0
  205. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/completions/shell_completions.py +0 -0
  206. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/file_icons/color_for_format.py +0 -0
  207. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/file_icons/nerd_icons.py +0 -0
  208. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/input/__init__.py +0 -0
  209. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/input/input_prompts.py +0 -0
  210. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/input/inquirer_settings.py +0 -0
  211. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/input/param_inputs.py +0 -0
  212. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/input/shell_confirm.py +0 -0
  213. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/output/__init__.py +0 -0
  214. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/output/kerm_code_utils.py +0 -0
  215. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/output/kerm_codes.py +0 -0
  216. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/output/kmarkdown.py +0 -0
  217. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/output/shell_formatting.py +0 -0
  218. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/output/shell_output.py +0 -0
  219. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/shell_main.py +0 -0
  220. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/ui/__init__.py +0 -0
  221. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/ui/shell_results.py +0 -0
  222. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/ui/shell_syntax.py +0 -0
  223. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/utils/exception_printing.py +0 -0
  224. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/utils/native_utils.py +0 -0
  225. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/utils/shell_function_wrapper.py +0 -0
  226. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/shell/version.py +0 -0
  227. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/__init__.py +0 -0
  228. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/api_utils/api_retries.py +0 -0
  229. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/api_utils/cache_requests_limited.py +0 -0
  230. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/api_utils/gather_limited.py +0 -0
  231. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/api_utils/http_utils.py +0 -0
  232. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/api_utils/multitask_gather.py +0 -0
  233. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/api_utils/progress_protocol.py +0 -0
  234. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/__init__.py +0 -0
  235. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/format_utils.py +0 -0
  236. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/function_inspect.py +0 -0
  237. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/import_utils.py +0 -0
  238. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/lazyobject.py +0 -0
  239. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/obj_replace.py +0 -0
  240. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/parse_docstring.py +0 -0
  241. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/parse_key_vals.py +0 -0
  242. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/parse_shell_args.py +0 -0
  243. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/s3_utils.py +0 -0
  244. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/stack_traces.py +0 -0
  245. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/task_stack.py +0 -0
  246. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/testing.py +0 -0
  247. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/type_utils.py +0 -0
  248. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/uniquifier.py +0 -0
  249. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/url.py +0 -0
  250. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/common/url_slice.py +0 -0
  251. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/errors.py +0 -0
  252. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_formats/chat_format.py +0 -0
  253. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_utils/__init__.py +0 -0
  254. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_utils/csv_utils.py +0 -0
  255. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_utils/dir_info.py +0 -0
  256. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_utils/file_ext.py +0 -0
  257. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_utils/file_formats.py +0 -0
  258. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_utils/file_formats_model.py +0 -0
  259. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_utils/file_sort_filter.py +0 -0
  260. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_utils/file_walk.py +0 -0
  261. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_utils/filename_parsing.py +0 -0
  262. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_utils/ignore_files.py +0 -0
  263. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_utils/mtime_cache.py +0 -0
  264. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/file_utils/path_utils.py +0 -0
  265. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/lang_utils/__init__.py +0 -0
  266. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/lang_utils/capitalization.py +0 -0
  267. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/rich_custom/__init__.py +0 -0
  268. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/rich_custom/ansi_cell_len.py +0 -0
  269. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/rich_custom/multitask_status.py +0 -0
  270. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/rich_custom/rich_char_transform.py +0 -0
  271. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/rich_custom/rich_indent.py +0 -0
  272. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/rich_custom/rich_markdown_fork.py +0 -0
  273. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/text_handling/doc_normalization.py +0 -0
  274. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/text_handling/escape_html_tags.py +0 -0
  275. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/text_handling/markdown_footnotes.py +0 -0
  276. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/text_handling/markdown_render.py +0 -0
  277. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/text_handling/markdown_utils.py +0 -0
  278. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/text_handling/markdownify_utils.py +0 -0
  279. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/utils/text_handling/unified_diffs.py +0 -0
  280. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_content/canon_url.py +0 -0
  281. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_content/dir_store.py +0 -0
  282. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_content/file_cache_utils.py +0 -0
  283. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_content/file_processing.py +0 -0
  284. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_content/local_file_cache.py +0 -0
  285. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_content/web_extract.py +0 -0
  286. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_content/web_extract_justext.py +0 -0
  287. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_content/web_extract_readabilipy.py +0 -0
  288. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_content/web_fetch.py +0 -0
  289. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_content/web_page_model.py +0 -0
  290. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/__init__.py +0 -0
  291. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/tabbed_webpage.py +0 -0
  292. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/template_render.py +0 -0
  293. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/base_styles.css.jinja +0 -0
  294. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/base_webpage.html.jinja +0 -0
  295. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/components/toc_scripts.js.jinja +0 -0
  296. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/components/toc_styles.css.jinja +0 -0
  297. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/components/tooltip_scripts.js.jinja +0 -0
  298. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/components/tooltip_styles.css.jinja +0 -0
  299. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/components/youtube_popover_scripts.js.jinja +0 -0
  300. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/components/youtube_popover_styles.css.jinja +0 -0
  301. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/content_styles.css.jinja +0 -0
  302. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/explain_view.html.jinja +0 -0
  303. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/item_view.html.jinja +0 -0
  304. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/simple_webpage.html.jinja +0 -0
  305. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/templates/tabbed_webpage.html.jinja +0 -0
  306. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/web_gen/webpage_render.py +0 -0
  307. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/workspaces/__init__.py +0 -0
  308. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/workspaces/param_state.py +0 -0
  309. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/workspaces/selections.py +0 -0
  310. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/workspaces/source_items.py +0 -0
  311. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/workspaces/workspace_dirs.py +0 -0
  312. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/workspaces/workspace_output.py +0 -0
  313. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/workspaces/workspace_registry.py +0 -0
  314. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/workspaces/workspaces.py +0 -0
  315. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xonsh_custom/command_nl_utils.py +0 -0
  316. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xonsh_custom/custom_shell.py +0 -0
  317. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xonsh_custom/customize_prompt.py +0 -0
  318. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xonsh_custom/load_into_xonsh.py +0 -0
  319. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xonsh_custom/shell_load_commands.py +0 -0
  320. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xonsh_custom/shell_which.py +0 -0
  321. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xonsh_custom/xonsh_completers.py +0 -0
  322. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xonsh_custom/xonsh_env.py +0 -0
  323. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xonsh_custom/xonsh_keybindings.py +0 -0
  324. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xonsh_custom/xonsh_modern_tools.py +0 -0
  325. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xonsh_custom/xonsh_ranking_completer.py +0 -0
  326. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xontrib/fnm.py +0 -0
  327. {kash_shell-0.3.35 → kash_shell-0.3.36}/src/kash/xontrib/kash_extension.py +0 -0
  328. {kash_shell-0.3.35 → kash_shell-0.3.36}/tests/file_storage/test_file_store.py +0 -0
  329. {kash_shell-0.3.35 → kash_shell-0.3.36}/tests/kash/utils/api_utils/test_gather_limited.py +0 -0
  330. {kash_shell-0.3.35 → kash_shell-0.3.36}/tests/kash/utils/file_utils/test_csv_utils.py +0 -0
  331. {kash_shell-0.3.35 → kash_shell-0.3.36}/tests/kash/utils/rich_custom/test_multitask_status.py +0 -0
  332. {kash_shell-0.3.35 → kash_shell-0.3.36}/tests/model/test_item_serialization.py +0 -0
  333. {kash_shell-0.3.35 → kash_shell-0.3.36}/tests/shell/input/interactive_input_test.py +0 -0
  334. {kash_shell-0.3.35 → kash_shell-0.3.36}/tests/test_shell.py +0 -0
  335. {kash_shell-0.3.35 → kash_shell-0.3.36}/tests/utils/text_handling/test_markdown_footnotes.py +0 -0
  336. {kash_shell-0.3.35 → kash_shell-0.3.36}/tests/web_gen/test_social_metadata.py +0 -0
@@ -1,5 +1,5 @@
1
1
  # Changes here will be overwritten by Copier. Do not edit manually.
2
- _commit: v0.2.14
2
+ _commit: v0.2.19
3
3
  _src_path: gh:jlevy/simple-modern-uv
4
4
  package_author_email: joshua@cal.berkeley.edu
5
5
  package_author_name: Joshua Levy
@@ -7,7 +7,7 @@ alwaysApply: true
7
7
 
8
8
  **Your fundamental responsibility:** Remember you are a senior engineer and have a
9
9
  serious responsibility to be clear, factual, think step by step and be systematic,
10
- express expert opinion, and make use of the user's attention wisely.
10
+ express expert opinion, and make use of the users attention wisely.
11
11
 
12
12
  **Rules must be followed:** It is your responsibility to carefully read these rules as
13
13
  well as Python or other language-specific rules included here.
@@ -22,19 +22,19 @@ Therefore:
22
22
  confirmation.
23
23
 
24
24
  - If you can think of a much better approach that the user requests, be sure to mention
25
- it. It's your responsibility to suggest approaches that lead to better, simpler
25
+ it. Its your responsibility to suggest approaches that lead to better, simpler
26
26
  solutions.
27
27
 
28
- - Give thoughtful opinions on better/worse approaches, but NEVER say "great idea!"
29
- or "good job" or other compliments, encouragement, or non-essential banter.
28
+ - Give thoughtful opinions on better/worse approaches, but NEVER say great idea!”
29
+ or good job or other compliments, encouragement, or non-essential banter.
30
30
  Your job is to give expert opinions and to solve problems, not to motivate the user.
31
31
 
32
32
  - Avoid gratuitous enthusiasm or generalizations.
33
- Use thoughtful comparisons like saying which code is "cleaner" but don't congratulate
33
+ Use thoughtful comparisons like saying which code is cleaner but dont congratulate
34
34
  yourself. Avoid subjective descriptions.
35
- For example, don't say "I've meticulously improved the code and it is in great shape!"
35
+ For example, dont say Ive meticulously improved the code and it is in great shape!”
36
36
  That is useless generalization.
37
- Instead, specifically say what you've done, e.g., "I've added types, including
37
+ Instead, specifically say what youve done, e.g., "Ive added types, including
38
38
  generics, to all the methods in `Foo` and fixed all linter errors."
39
39
 
40
40
  # General Coding Guidelines
@@ -49,17 +49,17 @@ Therefore:
49
49
  - DO NOT repeat in comments what is obvious from the names of functions or variables or
50
50
  types.
51
51
 
52
- - DO NOT include comments that reflect what you did, such as "Added this function" as
52
+ - DO NOT include comments that reflect what you did, such as Added this function as
53
53
  this is meaningless to anyone reading the code later.
54
54
  (Instead, describe in your message to the user any other contextual information.)
55
55
 
56
- - DO NOT use fancy or needlessly decorated headings like "===== MIGRATION TOOLS ====="
56
+ - DO NOT use fancy or needlessly decorated headings like “===== MIGRATION TOOLS =====”
57
57
  in comments
58
58
 
59
59
  - DO NOT number steps in comments.
60
60
  These are hard to maintain if the code changes.
61
- NEVER DO THIS: "// Step 3: Fetch the data from the cache"\
62
- This is fine: "// Now fetch the data from the cache"
61
+ NEVER DO THIS: “// Step 3: Fetch the data from the cache”\
62
+ This is fine: “// Now fetch the data from the cache
63
63
 
64
64
  - DO NOT use emojis or special unicode characters like ① or • or – or — in comments.
65
65
 
@@ -87,7 +87,7 @@ Always use full type annotations, generics, and other modern practices.
87
87
  - Use pathlib `Path` instead of strings.
88
88
  Use `Path(filename).read_text()` instead of two-line `with open(...)` blocks.
89
89
 
90
- - Use strif's `atomic_output_file` context manager when writing files to ensure output
90
+ - Use strifs `atomic_output_file` context manager when writing files to ensure output
91
91
  files are written atomically.
92
92
 
93
93
  ## Use Modern Python Practices
@@ -112,7 +112,7 @@ Always use full type annotations, generics, and other modern practices.
112
112
 
113
113
  - You can run such individual tests with `uv run pytest -s src/.../path/to/test`
114
114
 
115
- - Don't add docs to assertions unless it's not obvious what they're checking - the
115
+ - Dont add docs to assertions unless its not obvious what theyre checking - the
116
116
  assertion appears in the stack trace.
117
117
  Do NOT write `assert x == 5, "x should be 5"`. Do NOT write `assert x == 5 # Check if
118
118
  x is 5`. That is redundant.
@@ -122,7 +122,7 @@ Always use full type annotations, generics, and other modern practices.
122
122
  assertions that confirm the value of a constant setting.
123
123
 
124
124
  - NEVER write `assert False`. If a test reaches an unexpected branch and must fail
125
- explicitly, `raise AssertionError("Explanation")` instead.
125
+ explicitly, `raise AssertionError("Some explanation")` instead.
126
126
  This is best typical best practice in Python since assertions can be removed with
127
127
  optimization.
128
128
 
@@ -132,6 +132,21 @@ Always use full type annotations, generics, and other modern practices.
132
132
  This is also preferable because then simple tests have no explicit pytest dependencies
133
133
  and can be placed in code anywhere.
134
134
 
135
+ - DO NOT write trivial tests that test something we know already works, like
136
+ instantiating a Pydantic object.
137
+
138
+ ```python
139
+ class Link(BaseModel):
140
+ url: str
141
+ title: str = None
142
+
143
+ # DO NOT write tests like this. They are trivial and only create clutter!
144
+ def test_link_model():
145
+ link = Link(url="https://example.com", title="Example")
146
+ assert link.url == "https://example.com"
147
+ assert link.title == "Example"
148
+ ```
149
+
135
150
  ## Types and Type Annotations
136
151
 
137
152
  - Use modern union syntax: `str | None` instead of `Optional[str]`, `dict[str]` instead
@@ -142,7 +157,7 @@ Always use full type annotations, generics, and other modern practices.
142
157
  - Use modern enums like `StrEnum` if appropriate.
143
158
 
144
159
  - One exception to common practice on enums: If an enum has many values that are
145
- strings, and they have a literal value as a string (like in a JSON protocol), it's
160
+ strings, and they have a literal value as a string (like in a JSON protocol), its
146
161
  fine to use lower_snake_case for enum values to match the actual value.
147
162
  This is more readable than LONG_ALL_CAPS_VALUES, and you can simply set the value to
148
163
  be the same as the name for each.
@@ -228,7 +243,7 @@ Always use full type annotations, generics, and other modern practices.
228
243
  - For classes with many methods, use a concise docstring on the class that explains all
229
244
  the common information, and avoid repeating the same information on every method.
230
245
 
231
- - Docstrings should provide context or as concisely as possible explain "why", not
246
+ - Docstrings should provide context or as concisely as possible explain why”, not
232
247
  obvious details evident from the class names, function names, parameter names, and
233
248
  type annotations.
234
249
 
@@ -240,10 +255,10 @@ Always use full type annotations, generics, and other modern practices.
240
255
  name, variable name, or types.
241
256
  That is silly and obvious and makes the code longer for no reason.
242
257
 
243
- - Do NOT list args and return values if they're obvious.
258
+ - Do NOT list args and return values if theyre obvious.
244
259
  In the above examples, you do not need and `Arguments:` or `Returns:` section, since
245
- their meaning as obvious from context.
246
- do list these if there are many arguments and their meaning isn't clear.
260
+ sections as it is obvious from context.
261
+ do list these if there are many arguments and their meaning isnt clear.
247
262
  If it returns a less obvious type like a tuple, do explain in the pydoc.
248
263
 
249
264
  - Exported/public variables, functions, or methods SHOULD have concise docstrings.
@@ -42,7 +42,7 @@ jobs:
42
42
  uses: astral-sh/setup-uv@v5
43
43
  with:
44
44
  # Update this as needed:
45
- version: "0.7.13"
45
+ version: "0.9.5"
46
46
  enable-cache: true
47
47
  python-version: ${{ matrix.python-version }}
48
48
 
@@ -25,7 +25,7 @@ jobs:
25
25
  - name: Install uv (official Astral action)
26
26
  uses: astral-sh/setup-uv@v5
27
27
  with:
28
- version: "0.7.13"
28
+ version: "0.9.5"
29
29
  enable-cache: true
30
30
  python-version: "3.12"
31
31
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kash-shell
3
- Version: 0.3.35
3
+ Version: 0.3.36
4
4
  Summary: The knowledge agent shell (core)
5
5
  Project-URL: Repository, https://github.com/jlevy/kash-shell
6
6
  Author-email: Joshua Levy <joshua@cal.berkeley.edu>
@@ -29,6 +29,7 @@ def windowed_llm_transform(
29
29
  windowing: WindowSettings | None,
30
30
  diff_filter: DiffFilter | None = None,
31
31
  check_no_results: bool = True,
32
+ enable_web_search: bool = False,
32
33
  ) -> TextDoc:
33
34
  def doc_transform(input_doc: TextDoc) -> TextDoc:
34
35
  return TextDoc.from_text(
@@ -41,6 +42,7 @@ def windowed_llm_transform(
41
42
  input=input_doc.reassemble(),
42
43
  body_template=template,
43
44
  check_no_results=check_no_results,
45
+ enable_web_search=enable_web_search,
44
46
  ).content
45
47
  )
46
48
  )
@@ -67,6 +69,7 @@ def llm_transform_str(options: LLMOptions, input_str: str, check_no_results: boo
67
69
  input_str,
68
70
  options.windowing,
69
71
  diff_filter=options.diff_filter,
72
+ enable_web_search=options.enable_web_search,
70
73
  ).reassemble()
71
74
  else:
72
75
  log.info(
@@ -81,6 +84,7 @@ def llm_transform_str(options: LLMOptions, input_str: str, check_no_results: boo
81
84
  body_template=options.body_template,
82
85
  input=input_str,
83
86
  check_no_results=check_no_results,
87
+ enable_web_search=options.enable_web_search,
84
88
  ).content
85
89
 
86
90
  return result_str
@@ -485,6 +485,9 @@ class FileStore(Workspace):
485
485
  If `with_sidematter` is true, will copy any sidematter files (metadata/assets) to
486
486
  the destination.
487
487
  """
488
+ # TODO: Make sure importing a text item that already has
489
+ # frontmatter doesn't accidentally duplicate the frontmatter
490
+
488
491
  from kash.file_storage.item_file_format import read_item
489
492
  from kash.web_content.canon_url import canonicalize_url
490
493
 
@@ -531,6 +534,7 @@ class FileStore(Workspace):
531
534
  # This will read the file with or without frontmatter.
532
535
  # We are importing so we want to drop the external path so we save the body.
533
536
  item = read_item(path, self.base_dir)
537
+ log.info("Imported text item: %s", item)
534
538
  item.external_path = None
535
539
 
536
540
  if item.type and as_type and item.type != as_type:
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import time
4
4
  from dataclasses import dataclass
5
- from typing import TYPE_CHECKING, cast
5
+ from typing import TYPE_CHECKING, Any, cast
6
6
 
7
7
  from flowmark import Wrap, fill_text
8
8
  from funlog import format_duration, log_calls
@@ -51,6 +51,7 @@ class LLMCompletionResult:
51
51
  message: LiteLLMMessage
52
52
  content: str
53
53
  citations: CitationList | None
54
+ tool_calls: list[dict[str, Any]] | None = None
54
55
 
55
56
  @property
56
57
  def content_with_citations(self) -> str:
@@ -59,40 +60,111 @@ class LLMCompletionResult:
59
60
  content = content + "\n\n" + self.citations.as_markdown_footnotes()
60
61
  return content
61
62
 
63
+ @property
64
+ def has_tool_calls(self) -> bool:
65
+ """Check if the response contains tool calls."""
66
+ return bool(self.tool_calls)
67
+
68
+ @property
69
+ def tool_call_names(self) -> list[str]:
70
+ """Get list of tool names that were called."""
71
+ if not self.tool_calls:
72
+ return []
73
+ names = []
74
+ for call in self.tool_calls:
75
+ # Handle both LiteLLM objects and dict representations
76
+ if hasattr(call, "function") and hasattr(getattr(call, "function", None), "name"):
77
+ # LiteLLM object format
78
+ names.append(f"{call.function.name}()") # pyright: ignore[reportAttributeAccessIssue]
79
+ elif isinstance(call, dict) and call.get("function", {}).get("name"):
80
+ # Dict format
81
+ names.append(f"{call['function']['name']}()")
82
+ else:
83
+ names.append(str(call))
84
+ return names
85
+
62
86
 
63
87
  @log_calls(level="info")
64
88
  def llm_completion(
65
89
  model: LLMName,
66
90
  messages: list[dict[str, str]],
67
91
  save_objects: bool = True,
68
- response_format: dict | type[BaseModel] | None = None,
92
+ response_format: dict[str, Any] | type[BaseModel] | None = None,
93
+ tools: list[dict[str, Any]] | None = None,
94
+ enable_web_search: bool = False,
69
95
  **kwargs,
70
96
  ) -> LLMCompletionResult:
71
97
  """
72
98
  Perform an LLM completion with LiteLLM.
99
+
100
+ Args:
101
+ model: The LLM model to use
102
+ messages: Chat messages
103
+ save_objects: Whether to save chat history
104
+ response_format: Response format specification
105
+ tools: List of tools available for function calling (e.g., web_search)
106
+ enable_web_search: If True, automatically add web search tools for the model
107
+ **kwargs: Additional LiteLLM parameters
73
108
  """
74
- import litellm
75
109
  from litellm.types.utils import Choices, ModelResponse
76
110
 
77
111
  init_litellm()
78
112
 
113
+ # Prepare completion parameters
114
+ completion_params = {
115
+ "model": model.litellm_name,
116
+ "messages": messages,
117
+ **kwargs,
118
+ }
119
+
120
+ # Auto-enable web search if requested
121
+ if enable_web_search:
122
+ import litellm
123
+
124
+ if litellm.supports_web_search(model=model.litellm_name):
125
+ log.message("Enabling web search for model %s", model.litellm_name)
126
+ completion_params["web_search_options"] = {"search_context_size": "medium"}
127
+ else:
128
+ log.warning("Web search requested but not supported by model %s", model.litellm_name)
129
+
79
130
  chat_history = ChatHistory.from_dicts(messages)
131
+
132
+ # Enhanced logging to detect tool use
133
+ tools_info = f", {len(tools)} tools" if tools else ", no tools"
80
134
  log.info(
81
- "Calling LLM completion from %s on %s, response_format=%s",
135
+ "Calling LLM completion from %s on %s, response_format=%s%s",
82
136
  model.litellm_name,
83
137
  chat_history.size_summary(),
84
138
  response_format,
139
+ tools_info,
85
140
  )
86
141
 
142
+ if tools:
143
+ tool_names = []
144
+ for tool in tools:
145
+ if tool.get("type") == "function":
146
+ tool_names.append(tool.get("function", {}).get("name", "unknown"))
147
+ elif tool.get("type") == "native_web_search":
148
+ tool_names.append("native_web_search")
149
+ else:
150
+ tool_names.append(tool.get("type", "unknown"))
151
+
152
+ log.message("Tools enabled: %s", tool_names)
153
+
87
154
  start_time = time.time()
155
+
156
+ if response_format:
157
+ completion_params["response_format"] = response_format
158
+
159
+ if tools:
160
+ completion_params["tools"] = tools
161
+ log.info("Enabling function calling with %d tools", len(tools))
162
+
163
+ import litellm
164
+
88
165
  llm_output = cast(
89
166
  ModelResponse,
90
- litellm.completion(
91
- model.litellm_name,
92
- messages=messages,
93
- response_format=response_format,
94
- **kwargs,
95
- ), # pyright: ignore
167
+ litellm.completion(**completion_params), # pyright: ignore
96
168
  )
97
169
  elapsed = time.time() - start_time
98
170
 
@@ -100,23 +172,47 @@ def llm_completion(
100
172
 
101
173
  message = choices.message
102
174
 
175
+ # Extract tool calls from the response
176
+ tool_calls = getattr(message, "tool_calls", None)
177
+ tool_calls_list = list(tool_calls) if tool_calls else None
178
+
103
179
  # Just sanity checking and logging.
104
180
  content = choices.message.content
105
181
  if not content or not isinstance(content, str):
106
182
  raise ApiResultError(f"LLM completion failed: {model.litellm_name}: {llm_output}")
107
183
 
184
+ # Create the result object with tool calls
185
+ citations = llm_output.get("citations", None)
186
+ result = LLMCompletionResult(
187
+ message=message,
188
+ content=content,
189
+ citations=CitationList(citations=citations) if citations else None,
190
+ tool_calls=tool_calls_list,
191
+ )
192
+
193
+ # Log tool calls if present
194
+ if result.has_tool_calls:
195
+ tool_count = len(result.tool_calls or [])
196
+ log.message("LLM executed %d function calls: %s", tool_count, result.tool_call_names)
197
+ log.message(
198
+ "⚠️ Function calls require implementation - LLM requested tools but no handlers are implemented"
199
+ )
200
+
201
+ # Performance logging
108
202
  total_input_len = sum(len(m["content"]) for m in messages)
109
203
  speed = len(content) / elapsed
204
+ tool_count = len(result.tool_calls or []) if result.has_tool_calls else 0
205
+ tool_info = f", {tool_count} tool calls" if result.has_tool_calls else ""
110
206
  log.info(
111
207
  f"{EMOJI_TIMING} LLM completion from {model.litellm_name} in {format_duration(elapsed)}: "
112
208
  f"input {total_input_len} chars in {len(messages)} messages, output {len(content)} chars "
113
- f"({speed:.0f} char/s)"
209
+ f"({speed:.0f} char/s){tool_info}"
114
210
  )
115
211
 
116
- citations = llm_output.get("citations", None)
117
-
118
212
  if save_objects:
119
213
  metadata = {"citations": citations} if citations else {}
214
+ if result.has_tool_calls:
215
+ metadata["tool_calls"] = len(result.tool_calls or [])
120
216
  chat_history.messages.append(
121
217
  ChatMessage(role=ChatRole.assistant, content=content, metadata=metadata)
122
218
  )
@@ -128,11 +224,7 @@ def llm_completion(
128
224
  file_ext="yml",
129
225
  )
130
226
 
131
- return LLMCompletionResult(
132
- message=message,
133
- content=content,
134
- citations=CitationList(citations=citations) if citations else None,
135
- )
227
+ return result
136
228
 
137
229
 
138
230
  def llm_template_completion(
@@ -143,7 +235,9 @@ def llm_template_completion(
143
235
  previous_messages: list[dict[str, str]] | None = None,
144
236
  save_objects: bool = True,
145
237
  check_no_results: bool = True,
146
- response_format: dict | type[BaseModel] | None = None,
238
+ response_format: dict[str, Any] | type[BaseModel] | None = None,
239
+ tools: list[dict[str, Any]] | None = None,
240
+ enable_web_search: bool = False,
147
241
  **kwargs,
148
242
  ) -> LLMCompletionResult:
149
243
  """
@@ -169,6 +263,8 @@ def llm_template_completion(
169
263
  ],
170
264
  save_objects=save_objects,
171
265
  response_format=response_format,
266
+ tools=tools,
267
+ enable_web_search=enable_web_search,
172
268
  **kwargs,
173
269
  )
174
270
 
@@ -28,22 +28,23 @@ class LLM(LLMName, Enum):
28
28
  gpt_4_1 = LLMName("gpt-4.1")
29
29
  gpt_4o = LLMName("gpt-4o")
30
30
  gpt_4o_mini = LLMName("gpt-4o-mini")
31
+ gpt_4o_search_preview = LLMName("gpt-4o-search-preview")
31
32
  gpt_4 = LLMName("gpt-4")
32
33
  gpt_4_1_mini = LLMName("gpt-4.1-mini")
33
34
  gpt_4_1_nano = LLMName("gpt-4.1-nano")
34
35
 
35
- # https://docs.anthropic.com/en/docs/about-claude/models/all-models
36
+ # https://docs.claude.com/en/docs/about-claude/models
36
37
 
37
- claude_4_1_opus = LLMName("claude-opus-4-1")
38
- claude_4_opus = LLMName("claude-opus-4-20250514")
39
- claude_4_sonnet = LLMName("claude-sonnet-4-20250514")
40
- claude_3_7_sonnet = LLMName("claude-3-7-sonnet-latest")
41
- claude_3_5_haiku = LLMName("claude-3-5-haiku-latest")
38
+ claude_sonnet_4_5 = LLMName("claude-sonnet-4-5-20250929")
39
+ claude_haiku_4_5 = LLMName("claude-haiku-4-5-20251001")
40
+ claude_opus_4_1 = LLMName("claude-opus-4-1-20250805")
41
+ claude_sonnet_4 = LLMName("claude-sonnet-4-20250514")
42
+ claude_opus_4 = LLMName("claude-opus-4-20250514")
42
43
 
43
44
  # https://ai.google.dev/gemini-api/docs/models
44
45
  gemini_2_5_pro = LLMName("gemini/gemini-2.5-pro")
45
46
  gemini_2_5_flash = LLMName("gemini/gemini-2.5-flash")
46
- gemini_2_5_flash_lite = LLMName("gemini-2.5-flash-lite-preview-06-17")
47
+ gemini_2_5_flash_lite = LLMName("gemini/gemini-2.5-flash-lite")
47
48
 
48
49
  # https://docs.x.ai/docs/models
49
50
  xai_grok_3 = LLMName("xai/grok-3")
@@ -171,6 +171,7 @@ class LLMOptions:
171
171
  body_template: MessageTemplate = MessageTemplate("{body}")
172
172
  windowing: WindowSettings = WINDOW_NONE
173
173
  diff_filter: DiffFilter | None = None
174
+ enable_web_search: bool = False
174
175
 
175
176
  def updated_with(self, param_name: str, value: Any) -> LLMOptions:
176
177
  """Update option from an action parameter."""
@@ -543,8 +544,8 @@ class Action(ABC):
543
544
  def preassemble_result(self, context: ActionContext) -> ActionResult | None:
544
545
  """
545
546
  Actions can have a separate preliminary step to pre-assemble outputs. This allows
546
- us to determine the title and types for the output items and check if they were
547
- already generated before running slow or expensive actions.
547
+ us to determine thew expected shape of the expected output and check if it already
548
+ exists.
548
549
 
549
550
  For now, this only applies to actions with a single output, when `self.cacheable`
550
551
  is True.
@@ -568,7 +569,10 @@ class Action(ABC):
568
569
  self.name,
569
570
  )
570
571
  output_type = ItemType.doc
571
- primary_output = primary_input.derived_copy(context, 0, type=output_type)
572
+ output_format = context.action.output_format or primary_input.format
573
+ primary_output = primary_input.derived_copy(
574
+ context, 0, type=output_type, format=output_format
575
+ )
572
576
  log.info("Preassembled output: source %s, %s", primary_output.source, primary_output)
573
577
  return ActionResult([primary_output])
574
578
  else:
@@ -193,9 +193,16 @@ class ItemId:
193
193
  from kash.web_content.canon_url import canonicalize_url
194
194
 
195
195
  item_id = None
196
- if item.type == ItemType.resource and item.format == Format.url and item.url:
196
+ if (
197
+ item.type == ItemType.resource
198
+ and item.format == Format.url
199
+ and item.url
200
+ and not item.source
201
+ ):
202
+ # This is a plain URL resource, so its identity is its URL.
197
203
  item_id = ItemId(item.type, IdType.url, canonicalize_url(item.url))
198
204
  elif item.type == ItemType.concept and item.title:
205
+ # This is a concept, so its identity is its title.
199
206
  item_id = ItemId(item.type, IdType.concept, canonicalize_concept(item.title))
200
207
  elif item.source and item.source.cacheable and item.source.operation.has_known_inputs:
201
208
  # We know the source of this and if the action was cacheable, we can create
@@ -206,10 +206,10 @@ A list of parameter declarations, possibly with default values.
206
206
 
207
207
  # These are the default models for typical use cases.
208
208
  # The user may override them with parameters.
209
- DEFAULT_CAREFUL_LLM = LLM.gpt_5
210
- DEFAULT_STRUCTURED_LLM = LLM.gpt_5
211
- DEFAULT_STANDARD_LLM = LLM.gpt_5
212
- DEFAULT_FAST_LLM = LLM.gpt_5_mini
209
+ DEFAULT_CAREFUL_LLM = LLM.claude_sonnet_4_5
210
+ DEFAULT_STRUCTURED_LLM = LLM.claude_sonnet_4_5
211
+ DEFAULT_STANDARD_LLM = LLM.claude_sonnet_4_5
212
+ DEFAULT_FAST_LLM = LLM.claude_haiku_4_5
213
213
 
214
214
 
215
215
  # Parameters set globally such as in the workspace.
@@ -1,8 +1,9 @@
1
1
  {% extends "simple_webpage.html.jinja" %}
2
2
 
3
3
  {#
4
- Extends the simple page with a right-side YouTube popover player.
5
- Usage: pass page_template="youtube_webpage.html.jinja" to simple_webpage_render.
4
+ Extends the simple page with YouTube popover player.
5
+ Safe to use instead of simple_webpage.html.jinja since it only adds
6
+ functionality for YouTube if applicable.
6
7
  #}
7
8
 
8
9
  {% block custom_styles %}