tau-coding-agent 0.6.1__tar.gz → 0.6.2__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 (481) hide show
  1. {tau_coding_agent-0.6.1/tau_coding_agent.egg-info → tau_coding_agent-0.6.2}/PKG-INFO +1 -1
  2. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/pyproject.toml +1 -1
  3. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/agent/service.py +1 -8
  4. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/ask_user/component.py +177 -62
  5. tau_coding_agent-0.6.2/tau/builtins/extensions/ask_user/schema.py +142 -0
  6. tau_coding_agent-0.6.2/tau/builtins/extensions/ask_user/tool.py +181 -0
  7. tau_coding_agent-0.6.2/tau/builtins/extensions/sandbox/__init__.py +109 -0
  8. tau_coding_agent-0.6.2/tau/builtins/extensions/sandbox/manager.py +138 -0
  9. tau_coding_agent-0.6.2/tau/builtins/extensions/sandbox/manifest.json +69 -0
  10. tau_coding_agent-0.6.2/tau/builtins/extensions/sandbox/sandbox_tool.py +232 -0
  11. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/__init__.py +28 -0
  12. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/agents/context-builder.md +47 -0
  13. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/agents/delegate.md +9 -0
  14. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/agents/oracle.md +68 -0
  15. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/agents/planner.md +49 -0
  16. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/agents/researcher.md +48 -0
  17. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/agents/reviewer.md +72 -0
  18. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/agents/scout.md +41 -0
  19. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/agents/worker.md +36 -0
  20. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/agents.py +118 -0
  21. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/manifest.json +18 -0
  22. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/subagent_schema.py +75 -0
  23. tau_coding_agent-0.6.2/tau/builtins/extensions/subagent/subagent_tool.py +813 -0
  24. tau_coding_agent-0.6.2/tau/builtins/extensions/todo/__init__.py +165 -0
  25. tau_coding_agent-0.6.2/tau/builtins/extensions/todo/manifest.json +18 -0
  26. tau_coding_agent-0.6.2/tau/builtins/extensions/todo/todo_schema.py +69 -0
  27. tau_coding_agent-0.6.2/tau/builtins/extensions/todo/todo_tool.py +425 -0
  28. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/web/tools/fetch.py +1 -8
  29. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/skills/code-review/SKILL.md +1 -0
  30. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/skills/debug/SKILL.md +1 -0
  31. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/skills/git-commit/SKILL.md +1 -0
  32. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/tools/utils.py +1 -10
  33. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/console/cli.py +17 -0
  34. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/commands/extensions.py +21 -2
  35. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/commands/session.py +6 -26
  36. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/config_selector.py +1 -1
  37. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/extension_selector.py +1 -0
  38. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/message_list.py +20 -0
  39. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/model_selector.py +4 -11
  40. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/oauth_selector.py +1 -0
  41. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/session_selector.py +6 -9
  42. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/settings_selector.py +3 -3
  43. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/theme_selector.py +1 -0
  44. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/thinking_selector.py +1 -0
  45. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/voice_selector.py +1 -0
  46. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/session/manager.py +8 -6
  47. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/themes/loader.py +1 -0
  48. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/components/simple_picker.py +2 -1
  49. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/markdown.py +2 -1
  50. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/theme.py +7 -0
  51. tau_coding_agent-0.6.2/tau/utils/format.py +40 -0
  52. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2/tau_coding_agent.egg-info}/PKG-INFO +1 -1
  53. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau_coding_agent.egg-info/SOURCES.txt +23 -1
  54. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_ask_user_extension.py +1 -1
  55. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_gemini_generate.py +2 -1
  56. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_session_manager.py +21 -0
  57. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_session_trust_persist.py +50 -0
  58. tau_coding_agent-0.6.2/tests/test_subagent_context.py +288 -0
  59. tau_coding_agent-0.6.1/tau/builtins/extensions/ask_user/schema.py +0 -41
  60. tau_coding_agent-0.6.1/tau/builtins/extensions/ask_user/tool.py +0 -124
  61. tau_coding_agent-0.6.1/tests/test_subagents_extension.py +0 -271
  62. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/LICENSE +0 -0
  63. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/MANIFEST.in +0 -0
  64. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/README.md +0 -0
  65. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/architecture.md +0 -0
  66. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/auth.md +0 -0
  67. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/cli-reference.md +0 -0
  68. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/creating-tools.md +0 -0
  69. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/development.md +0 -0
  70. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/docs.json +0 -0
  71. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/engine.md +0 -0
  72. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/extension-settings.md +0 -0
  73. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/extensions.md +0 -0
  74. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/http-proxy.md +0 -0
  75. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/index.md +0 -0
  76. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/inference-providers.md +0 -0
  77. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/inference.md +0 -0
  78. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/installation.md +0 -0
  79. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/keybindings.md +0 -0
  80. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/messages.md +0 -0
  81. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/project-context.md +0 -0
  82. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/project-structure.md +0 -0
  83. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/prompts.md +0 -0
  84. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/python-api.md +0 -0
  85. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/quickstart.md +0 -0
  86. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/sessions.md +0 -0
  87. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/settings.md +0 -0
  88. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/skills.md +0 -0
  89. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/themes.md +0 -0
  90. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/tools.md +0 -0
  91. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/tui.md +0 -0
  92. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/docs/usage.md +0 -0
  93. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/setup.cfg +0 -0
  94. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/__init__.py +0 -0
  95. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/agent/__init__.py +0 -0
  96. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/agent/prompt/__init__.py +0 -0
  97. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/agent/prompt/builder.py +0 -0
  98. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/agent/prompt/types.py +0 -0
  99. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/agent/types.py +0 -0
  100. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/auth/manager.py +0 -0
  101. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/auth/storage.py +0 -0
  102. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/auth/types.py +0 -0
  103. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/__init__.py +0 -0
  104. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/commands/__init__.py +0 -0
  105. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/commands/clear.py +0 -0
  106. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/commands/compact.py +0 -0
  107. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/commands/reload.py +0 -0
  108. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/commands/session.py +0 -0
  109. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/ask_user/__init__.py +0 -0
  110. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/ask_user/manifest.json +0 -0
  111. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/btw/__init__.py +0 -0
  112. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/footer/__init__.py +0 -0
  113. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/footer/git.py +0 -0
  114. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/footer/model.py +0 -0
  115. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/footer/utils.py +0 -0
  116. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/header/__init__.py +0 -0
  117. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/watch/__init__.py +0 -0
  118. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/web/__init__.py +0 -0
  119. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/web/engines/__init__.py +0 -0
  120. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/web/engines/base.py +0 -0
  121. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/web/engines/ddgs_engine.py +0 -0
  122. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/web/engines/exa_engine.py +0 -0
  123. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/web/engines/jina_engine.py +0 -0
  124. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/web/engines/tavily_engine.py +0 -0
  125. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/web/manifest.json +0 -0
  126. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/web/tools/__init__.py +0 -0
  127. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/extensions/web/tools/search.py +0 -0
  128. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/models/__init__.py +0 -0
  129. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/models/audio.py +0 -0
  130. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/models/image.py +0 -0
  131. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/models/text.py +0 -0
  132. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/models/video.py +0 -0
  133. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/prompts/commit.md +0 -0
  134. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/prompts/docs.md +0 -0
  135. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/prompts/explain.md +0 -0
  136. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/prompts/fix.md +0 -0
  137. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/prompts/refactor.md +0 -0
  138. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/prompts/review.md +0 -0
  139. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/prompts/test.md +0 -0
  140. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/providers/__init__.py +0 -0
  141. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/providers/audio.py +0 -0
  142. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/providers/image.py +0 -0
  143. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/providers/text.py +0 -0
  144. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/providers/video.py +0 -0
  145. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/skills/skill-creator/LICENSE.txt +0 -0
  146. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/skills/skill-creator/SKILL.md +0 -0
  147. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/ayu-dark.yaml +0 -0
  148. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/catppuccin.yaml +0 -0
  149. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/dark.yaml +0 -0
  150. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/dracula.yaml +0 -0
  151. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/everforest.yaml +0 -0
  152. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/gruvbox.yaml +0 -0
  153. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/horizon.yaml +0 -0
  154. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/kanagawa.yaml +0 -0
  155. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/light.yaml +0 -0
  156. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/material-ocean.yaml +0 -0
  157. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/monokai.yaml +0 -0
  158. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/night-owl.yaml +0 -0
  159. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/nord.yaml +0 -0
  160. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/one-dark.yaml +0 -0
  161. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/rose-pine.yaml +0 -0
  162. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/solarized-dark.yaml +0 -0
  163. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/themes/tokyo-night.yaml +0 -0
  164. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/tools/__init__.py +0 -0
  165. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/tools/edit.py +0 -0
  166. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/tools/glob.py +0 -0
  167. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/tools/grep.py +0 -0
  168. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/tools/ls.py +0 -0
  169. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/tools/read.py +0 -0
  170. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/tools/terminal.py +0 -0
  171. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/builtins/tools/write.py +0 -0
  172. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/commands/__init__.py +0 -0
  173. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/commands/registry.py +0 -0
  174. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/commands/types.py +0 -0
  175. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/console/__init__.py +0 -0
  176. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/console/commands/__init__.py +0 -0
  177. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/console/commands/auth.py +0 -0
  178. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/console/commands/packages.py +0 -0
  179. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/console/commands/update.py +0 -0
  180. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/core/__init__.py +0 -0
  181. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/core/registry.py +0 -0
  182. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/engine/__init__.py +0 -0
  183. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/engine/service.py +0 -0
  184. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/engine/types.py +0 -0
  185. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/extensions/__init__.py +0 -0
  186. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/extensions/api.py +0 -0
  187. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/extensions/context.py +0 -0
  188. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/extensions/loader.py +0 -0
  189. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/extensions/runtime.py +0 -0
  190. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/extensions/settings.py +0 -0
  191. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/hooks/__init__.py +0 -0
  192. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/hooks/engine.py +0 -0
  193. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/hooks/inference.py +0 -0
  194. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/hooks/runtime.py +0 -0
  195. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/hooks/service.py +0 -0
  196. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/hooks/session.py +0 -0
  197. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/hooks/tui.py +0 -0
  198. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/hooks/types.py +0 -0
  199. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/__init__.py +0 -0
  200. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/__init__.py +0 -0
  201. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/audio/__init__.py +0 -0
  202. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/audio/base.py +0 -0
  203. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/audio/builtins.py +0 -0
  204. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/audio/elevenlabs_audio.py +0 -0
  205. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/audio/gemini_audio.py +0 -0
  206. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/audio/openai_audio.py +0 -0
  207. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/audio/registry.py +0 -0
  208. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/audio/sarvam_audio.py +0 -0
  209. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/audio/service.py +0 -0
  210. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/audio/utils.py +0 -0
  211. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/availability.py +0 -0
  212. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/image/__init__.py +0 -0
  213. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/image/base.py +0 -0
  214. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/image/builtins.py +0 -0
  215. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/image/gemini_image.py +0 -0
  216. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/image/openai_image.py +0 -0
  217. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/image/openrouter.py +0 -0
  218. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/image/registry.py +0 -0
  219. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/image/service.py +0 -0
  220. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/registry.py +0 -0
  221. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/__init__.py +0 -0
  222. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/anthropic_claude_code.py +0 -0
  223. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/anthropic_messages.py +0 -0
  224. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/anthropic_vertex.py +0 -0
  225. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/base.py +0 -0
  226. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/builtins.py +0 -0
  227. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/dialect.py +0 -0
  228. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/gemini_generate.py +0 -0
  229. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/github_copilot_chat.py +0 -0
  230. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/google_antigravity.py +0 -0
  231. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/google_vertex.py +0 -0
  232. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/mistral_chat.py +0 -0
  233. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/ollama_chat.py +0 -0
  234. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/openai_codex_responses.py +0 -0
  235. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/openai_completions.py +0 -0
  236. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/openai_responses.py +0 -0
  237. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/openai_vertex.py +0 -0
  238. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/registry.py +0 -0
  239. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/service.py +0 -0
  240. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/types.py +0 -0
  241. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/text/utils.py +0 -0
  242. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/video/__init__.py +0 -0
  243. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/video/base.py +0 -0
  244. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/video/builtins.py +0 -0
  245. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/video/fal_video.py +0 -0
  246. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/video/openrouter_video.py +0 -0
  247. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/video/registry.py +0 -0
  248. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/video/service.py +0 -0
  249. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/api/video/zai_video.py +0 -0
  250. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/model/__init__.py +0 -0
  251. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/model/registry.py +0 -0
  252. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/model/types.py +0 -0
  253. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/provider/__init__.py +0 -0
  254. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/provider/oauth/__init__.py +0 -0
  255. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/provider/oauth/anthropic_claude_code.py +0 -0
  256. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/provider/oauth/github_copilot.py +0 -0
  257. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/provider/oauth/google_antigravity.py +0 -0
  258. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/provider/oauth/openai_codex.py +0 -0
  259. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/provider/oauth/pkce.py +0 -0
  260. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/provider/oauth/types.py +0 -0
  261. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/provider/oauth/utils.py +0 -0
  262. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/provider/registry.py +0 -0
  263. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/provider/types.py +0 -0
  264. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/types.py +0 -0
  265. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/inference/utils.py +0 -0
  266. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/message/__init__.py +0 -0
  267. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/message/types.py +0 -0
  268. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/message/utils.py +0 -0
  269. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/__init__.py +0 -0
  270. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/__init__.py +0 -0
  271. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/agent_hooks.py +0 -0
  272. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/app.py +0 -0
  273. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/commands/__init__.py +0 -0
  274. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/commands/appearance.py +0 -0
  275. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/commands/auth.py +0 -0
  276. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/commands/context.py +0 -0
  277. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/commands/misc.py +0 -0
  278. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/commands/model.py +0 -0
  279. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/__init__.py +0 -0
  280. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/command_palette.py +0 -0
  281. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/file_picker.py +0 -0
  282. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/layout.py +0 -0
  283. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/overlays.py +0 -0
  284. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/selector_controller.py +0 -0
  285. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/tree_selector.py +0 -0
  286. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/components/trust_screen.py +0 -0
  287. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/input_handler.py +0 -0
  288. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/interactive/ui_context.py +0 -0
  289. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/print/__init__.py +0 -0
  290. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/rpc/__init__.py +0 -0
  291. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/rpc/mode.py +0 -0
  292. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/modes/rpc/types.py +0 -0
  293. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/packages/__init__.py +0 -0
  294. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/packages/manager.py +0 -0
  295. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/packages/types.py +0 -0
  296. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/packages/utils.py +0 -0
  297. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/prompts/expand.py +0 -0
  298. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/prompts/loader.py +0 -0
  299. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/prompts/registry.py +0 -0
  300. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/prompts/types.py +0 -0
  301. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/resources/__init__.py +0 -0
  302. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/resources/loader.py +0 -0
  303. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/resources/types.py +0 -0
  304. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/runtime/dependencies.py +0 -0
  305. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/runtime/service.py +0 -0
  306. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/runtime/types.py +0 -0
  307. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/session/branch_summarization.py +0 -0
  308. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/session/compaction.py +0 -0
  309. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/session/types.py +0 -0
  310. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/session/utils.py +0 -0
  311. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/settings/manager.py +0 -0
  312. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/settings/paths.py +0 -0
  313. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/settings/storage.py +0 -0
  314. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/settings/types.py +0 -0
  315. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/settings/utils.py +0 -0
  316. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/skills/loader.py +0 -0
  317. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/skills/registry.py +0 -0
  318. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/skills/types.py +0 -0
  319. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/telemetry/__init__.py +0 -0
  320. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/telemetry/service.py +0 -0
  321. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/telemetry/types.py +0 -0
  322. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/themes/registry.py +0 -0
  323. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/themes/types.py +0 -0
  324. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tool/__init__.py +0 -0
  325. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tool/registry.py +0 -0
  326. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tool/render.py +0 -0
  327. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tool/types.py +0 -0
  328. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/trust/__init__.py +0 -0
  329. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/trust/manager.py +0 -0
  330. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/trust/types.py +0 -0
  331. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/trust/utils.py +0 -0
  332. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/__init__.py +0 -0
  333. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/ansi_bridge.py +0 -0
  334. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/autocomplete.py +0 -0
  335. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/backend.py +0 -0
  336. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/buffer.py +0 -0
  337. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/component.py +0 -0
  338. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/components/__init__.py +0 -0
  339. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/components/box.py +0 -0
  340. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/components/editor.py +0 -0
  341. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/components/image.py +0 -0
  342. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/components/select_list.py +0 -0
  343. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/components/spinner.py +0 -0
  344. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/components/text_input.py +0 -0
  345. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/components/widget_bridge.py +0 -0
  346. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/frame.py +0 -0
  347. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/geometry.py +0 -0
  348. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/input.py +0 -0
  349. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/keybinding_hints.py +0 -0
  350. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/layout.py +0 -0
  351. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/palette.py +0 -0
  352. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/service.py +0 -0
  353. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/style.py +0 -0
  354. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/terminal.py +0 -0
  355. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/testing.py +0 -0
  356. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/text.py +0 -0
  357. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/utils.py +0 -0
  358. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widget.py +0 -0
  359. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/__init__.py +0 -0
  360. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/barchart.py +0 -0
  361. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/block.py +0 -0
  362. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/calendar.py +0 -0
  363. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/canvas.py +0 -0
  364. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/chart.py +0 -0
  365. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/clear.py +0 -0
  366. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/gauge.py +0 -0
  367. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/list.py +0 -0
  368. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/paragraph.py +0 -0
  369. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/scrollbar.py +0 -0
  370. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/sparkline.py +0 -0
  371. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/symbols.py +0 -0
  372. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/table.py +0 -0
  373. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/tui/widgets/tabs.py +0 -0
  374. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/utils/__init__.py +0 -0
  375. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/utils/http_proxy.py +0 -0
  376. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/utils/image_processing.py +0 -0
  377. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/utils/secrets.py +0 -0
  378. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau/utils/version_check.py +0 -0
  379. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau_coding_agent.egg-info/dependency_links.txt +0 -0
  380. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau_coding_agent.egg-info/entry_points.txt +0 -0
  381. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau_coding_agent.egg-info/requires.txt +0 -0
  382. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tau_coding_agent.egg-info/top_level.txt +0 -0
  383. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_agent_compaction.py +0 -0
  384. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_agent_hooks.py +0 -0
  385. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_agent_prompt.py +0 -0
  386. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_agent_types.py +0 -0
  387. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_ansi.py +0 -0
  388. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_ansi_bridge_legacy_image.py +0 -0
  389. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_audio_transcription_apis.py +0 -0
  390. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_auth_command.py +0 -0
  391. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_auth_manager.py +0 -0
  392. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_auth_storage.py +0 -0
  393. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_autocomplete_modifiers.py +0 -0
  394. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_branch_navigation.py +0 -0
  395. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_branch_summarization.py +0 -0
  396. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_builtin_tools.py +0 -0
  397. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_builtin_watch.py +0 -0
  398. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_cli_inputs.py +0 -0
  399. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_command_execution_policy.py +0 -0
  400. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_command_registry.py +0 -0
  401. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_compaction.py +0 -0
  402. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_component_buffer_bridge.py +0 -0
  403. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_diff.py +0 -0
  404. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_editor_protocol.py +0 -0
  405. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_engine_execution.py +0 -0
  406. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_engine_steering.py +0 -0
  407. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_engine_types.py +0 -0
  408. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_escape_behavior.py +0 -0
  409. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_extension_api.py +0 -0
  410. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_extension_lifecycle.py +0 -0
  411. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_footer_model.py +0 -0
  412. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_footer_utils.py +0 -0
  413. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_fuzzy.py +0 -0
  414. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_http_proxy.py +0 -0
  415. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_image_processing.py +0 -0
  416. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_inference_api_text_utils.py +0 -0
  417. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_inference_dialect.py +0 -0
  418. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_inference_error_utils.py +0 -0
  419. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_inference_types.py +0 -0
  420. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_inference_utils.py +0 -0
  421. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_keybindings.py +0 -0
  422. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_layout_render_cells.py +0 -0
  423. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_markdown.py +0 -0
  424. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_mcp_extension.py +0 -0
  425. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_message_list_frozen.py +0 -0
  426. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_message_types.py +0 -0
  427. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_message_utils.py +0 -0
  428. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_model_availability.py +0 -0
  429. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_model_command.py +0 -0
  430. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_model_registry.py +0 -0
  431. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_model_selector_modal.py +0 -0
  432. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_model_types.py +0 -0
  433. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_oauth_utils.py +0 -0
  434. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_package_resources.py +0 -0
  435. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_packages_utils.py +0 -0
  436. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_peer_extension.py +0 -0
  437. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_pkce.py +0 -0
  438. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_prompts_expand.py +0 -0
  439. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_prompts_loader.py +0 -0
  440. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_prompts_registry.py +0 -0
  441. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_provider_registry.py +0 -0
  442. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_resource_loader.py +0 -0
  443. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_rpc_mode.py +0 -0
  444. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_runtime_sdk.py +0 -0
  445. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_scrollback_raw_writes.py +0 -0
  446. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_scrollback_terminal.py +0 -0
  447. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_secrets.py +0 -0
  448. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_select_list_render_cells.py +0 -0
  449. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_selector_controller.py +0 -0
  450. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_session_types.py +0 -0
  451. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_session_utils.py +0 -0
  452. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_settings_manager.py +0 -0
  453. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_settings_paths.py +0 -0
  454. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_settings_storage.py +0 -0
  455. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_settings_utils.py +0 -0
  456. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_skills_loader.py +0 -0
  457. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_skills_registry.py +0 -0
  458. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_telemetry.py +0 -0
  459. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_text_input.py +0 -0
  460. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_text_input_render_cells.py +0 -0
  461. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_text_llm_invoke.py +0 -0
  462. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_theme_loader.py +0 -0
  463. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_themes_registry.py +0 -0
  464. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_thinking_render.py +0 -0
  465. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_tool_registry.py +0 -0
  466. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_tool_render.py +0 -0
  467. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_trust_manager.py +0 -0
  468. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_trust_utils.py +0 -0
  469. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_tui_capabilities.py +0 -0
  470. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_tui_child_rows.py +0 -0
  471. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_tui_input.py +0 -0
  472. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_tui_layout_sizing.py +0 -0
  473. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_tui_public_api.py +0 -0
  474. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_tui_renderer.py +0 -0
  475. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_tui_select_list.py +0 -0
  476. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_tui_theme.py +0 -0
  477. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_tui_utils.py +0 -0
  478. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_ui_context.py +0 -0
  479. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_utils_hashline.py +0 -0
  480. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_version_check.py +0 -0
  481. {tau_coding_agent-0.6.1 → tau_coding_agent-0.6.2}/tests/test_voice_selector.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tau-coding-agent
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: A self-extensible agent CLI with terminal UI, multi-provider LLM support, session management with branching, and a plugin system for tools and commands
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tau-coding-agent"
7
- version = "0.6.1"
7
+ version = "0.6.2"
8
8
  description = "A self-extensible agent CLI with terminal UI, multi-provider LLM support, session management with branching, and a plugin system for tools and commands"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -20,6 +20,7 @@ from tau.message.utils import strip_unusable_trailing_assistant
20
20
  from tau.session.compaction import CompactionSettings
21
21
  from tau.session.utils import to_llm_messages as _to_llm_messages
22
22
  from tau.tool.types import ToolInvocation, ToolResult
23
+ from tau.utils.format import human_size as _fmt_size
23
24
 
24
25
  _log = logging.getLogger(__name__)
25
26
 
@@ -33,14 +34,6 @@ _TOOL_CAP_LINES = 2000 # DEFAULT_MAX_LINES
33
34
  _TOOL_LINE_CAP_BYTES = 2 * 1024 # 2 KB — max bytes for a single line
34
35
 
35
36
 
36
- def _fmt_size(n: int) -> str:
37
- if n < 1024:
38
- return f"{n}B"
39
- if n < 1024 * 1024:
40
- return f"{n / 1024:.1f}KB"
41
- return f"{n / (1024 * 1024):.1f}MB"
42
-
43
-
44
37
  if TYPE_CHECKING:
45
38
  from tau.engine.service import Engine
46
39
  from tau.runtime.service import Runtime
@@ -1,8 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import textwrap
3
4
  from typing import TYPE_CHECKING, Any
4
5
 
5
- from schema import AskUserOption # type: ignore[import-not-found]
6
+ from schema import FREEFORM_LABEL, AskUserOption # type: ignore[import-not-found]
6
7
 
7
8
  from tau.tui.component import Component
8
9
  from tau.tui.input import InputEvent, KeyEvent
@@ -11,8 +12,6 @@ if TYPE_CHECKING:
11
12
  from tau.tui.buffer import Buffer
12
13
  from tau.tui.geometry import Rect
13
14
 
14
- FREEFORM_LABEL = "Type something…"
15
-
16
15
 
17
16
  def _typed_char(event: KeyEvent) -> str | None:
18
17
  """Return the printable character a key event represents, or None.
@@ -34,6 +33,12 @@ class _AskUserComponent(Component):
34
33
  ML_VISIBLE_ROWS = 8
35
34
  ML_MIN_VISIBLE_ROWS = 4 # pad short buffers so the box visibly reads as multi-line
36
35
 
36
+ # Below this total width there's no room for a legible side-by-side preview
37
+ # column, so the option list just falls back to full width with no preview.
38
+ PREVIEW_MIN_TOTAL_WIDTH = 70
39
+ PREVIEW_GAP = 2
40
+ PREVIEW_MIN_BOX_HEIGHT = 6
41
+
37
42
  def __init__(
38
43
  self,
39
44
  question: str,
@@ -85,96 +90,206 @@ class _AskUserComponent(Component):
85
90
 
86
91
  # ── Render ────────────────────────────────────────────────────────────
87
92
 
93
+ def _has_preview_capable_options(self) -> bool:
94
+ return not self._allow_multiple and any(o.preview for o in self._options)
95
+
88
96
  def render_cells(self, area: Rect, buf: Buffer) -> int:
89
97
  from tau.tui.ansi_bridge import parse_ansi_wrapped_into
90
98
 
91
- def _plain(lines: list[str]) -> int:
99
+ def _write(lines: list[str], x: int, y: int, width: int) -> int:
92
100
  row = 0
93
101
  for line in lines:
94
- row += parse_ansi_wrapped_into(buf, area.x, area.y + row, line, area.width)
102
+ row += parse_ansi_wrapped_into(buf, x, y + row, line, width)
95
103
  return row
96
104
 
97
- inner: list[str] = []
105
+ header: list[str] = []
98
106
  if self._context:
99
107
  for line in self._context.splitlines():
100
- inner.append(f" \x1b[2m{line}\x1b[0m")
101
- inner.append("")
102
- inner.append(f" \x1b[1m{self._question}\x1b[0m")
103
- inner.append("")
104
-
108
+ header.append(f" \x1b[2m{line}\x1b[0m")
109
+ header.append("")
110
+ header.append(f" \x1b[1m{self._question}\x1b[0m")
111
+ header.append("")
112
+
113
+ header_rows = _write(header, area.x, area.y, area.width)
114
+ body_y = area.y + header_rows
115
+
116
+ show_preview = (
117
+ self._has_preview_capable_options() and area.width >= self.PREVIEW_MIN_TOTAL_WIDTH
118
+ )
119
+
120
+ left_width = min(46, max(30, area.width // 3)) if show_preview else area.width
121
+ content_lines, footer_lines = self._build_body_lines(left_width)
122
+
123
+ if not show_preview:
124
+ body_rows = _write(content_lines, area.x, body_y, area.width)
125
+ footer_rows = _write(footer_lines, area.x, body_y + body_rows, area.width)
126
+ return header_rows + body_rows + footer_rows
127
+
128
+ right_width = area.width - left_width - self.PREVIEW_GAP
129
+
130
+ preview: str | None = None
131
+ if self._cursor != self._freeform_index and self._options:
132
+ preview = self._options[self._cursor].preview
133
+
134
+ box_height = max(len(content_lines), self.PREVIEW_MIN_BOX_HEIGHT)
135
+ preview_box = self._build_preview_box(preview, right_width, box_height)
136
+
137
+ left_rows = _write(content_lines, area.x, body_y, left_width)
138
+ right_rows = _write(preview_box, area.x + left_width + self.PREVIEW_GAP, body_y, right_width)
139
+ col_rows = max(left_rows, right_rows)
140
+
141
+ # Footer spans the FULL width beneath both columns — it's not part of
142
+ # either column, so it never wraps just because the left column is
143
+ # narrow, and it visually separates from the preview box like the
144
+ # bottom nav-hint line in the reference screenshot.
145
+ footer_rows = _write(footer_lines, area.x, body_y + col_rows, area.width)
146
+ return header_rows + col_rows + footer_rows
147
+
148
+ def _build_body_lines(self, width: int) -> tuple[list[str], list[str]]:
149
+ """Everything below the header: the option list, or whichever freeform
150
+ editor is active. ``width`` is whatever column this ends up rendered
151
+ in (full width, or the left column next to a preview pane) — used to
152
+ wrap option descriptions so they don't run into the next row.
153
+
154
+ Returns ``(content_lines, footer_lines)``. The footer is kept separate
155
+ from the content so the caller can always render it full-width, even
156
+ when the content itself is confined to a narrow left column.
157
+ """
105
158
  if self._mode == "freeform" and self._multiline:
106
- self._clamp_ml_scroll()
107
- limit = self._ml_scroll_top + self.ML_VISIBLE_ROWS
108
- visible = self._ml_lines[self._ml_scroll_top : limit]
109
- for ri, line in enumerate(visible):
110
- abs_row = self._ml_scroll_top + ri
111
- if abs_row == self._ml_cursor_row:
112
- before = line[: self._ml_cursor_col]
113
- after = line[self._ml_cursor_col :]
114
- inner.append(f" {before}█{after}")
115
- else:
116
- inner.append(f" {line}")
117
- # Pad with blank rows (display-only, not part of the buffer) so an
118
- # empty/short answer still shows several rows — a visible cue that
119
- # this is a multi-line editor, not a single-line box.
120
- for _ in range(self.ML_MIN_VISIBLE_ROWS - len(visible)):
121
- inner.append("")
122
- total = len(self._ml_lines)
123
- if total > self.ML_VISIBLE_ROWS:
124
- pct = int(self._ml_scroll_top / max(1, total - self.ML_VISIBLE_ROWS) * 100)
125
- inner.append(f" \x1b[2m↕ {pct}%\x1b[0m")
126
- else:
127
- inner.append("")
128
- back = "Esc to cancel" if not self._options else "Esc to go back"
129
- inner.append(
130
- " \x1b[2mEnter to submit · \\+Enter or Shift+Enter for newline · "
131
- f"{back}\x1b[0m"
132
- )
133
- return _plain(inner)
134
-
159
+ return self._build_multiline_body()
135
160
  if self._mode == "freeform":
136
- inner.append(f" {self._freeform_value}█")
161
+ return self._build_singleline_body()
162
+ return self._build_list_body(width)
163
+
164
+ def _build_multiline_body(self) -> tuple[list[str], list[str]]:
165
+ inner: list[str] = []
166
+ self._clamp_ml_scroll()
167
+ limit = self._ml_scroll_top + self.ML_VISIBLE_ROWS
168
+ visible = self._ml_lines[self._ml_scroll_top : limit]
169
+ for ri, line in enumerate(visible):
170
+ abs_row = self._ml_scroll_top + ri
171
+ if abs_row == self._ml_cursor_row:
172
+ before = line[: self._ml_cursor_col]
173
+ after = line[self._ml_cursor_col :]
174
+ inner.append(f" {before}█{after}")
175
+ else:
176
+ inner.append(f" {line}")
177
+ # Pad with blank rows (display-only, not part of the buffer) so an
178
+ # empty/short answer still shows several rows — a visible cue that
179
+ # this is a multi-line editor, not a single-line box.
180
+ for _ in range(self.ML_MIN_VISIBLE_ROWS - len(visible)):
181
+ inner.append("")
182
+ total = len(self._ml_lines)
183
+ if total > self.ML_VISIBLE_ROWS:
184
+ pct = int(self._ml_scroll_top / max(1, total - self.ML_VISIBLE_ROWS) * 100)
185
+ inner.append(f" \x1b[2m↕ {pct}%\x1b[0m")
186
+ else:
137
187
  inner.append("")
138
- back = "Esc to cancel" if not self._options else "Esc to go back"
139
- inner.append(f" \x1b[2mEnter to submit · {back}\x1b[0m")
140
- return _plain(inner)
188
+ back = "Esc to cancel" if not self._options else "Esc to go back"
189
+ footer = [
190
+ "",
191
+ " \x1b[2mEnter to submit · \\+Enter or Shift+Enter for newline · "
192
+ f"{back}\x1b[0m",
193
+ ]
194
+ return inner, footer
195
+
196
+ def _build_singleline_body(self) -> tuple[list[str], list[str]]:
197
+ back = "Esc to cancel" if not self._options else "Esc to go back"
198
+ content = [f" {self._freeform_value}█"]
199
+ footer = ["", f" \x1b[2mEnter to submit · {back}\x1b[0m"]
200
+ return content, footer
201
+
202
+ # Left margin + hanging indent for wrapped description lines beneath a
203
+ # title row — matches the " ❯ 1. " prefix width closely enough to read as
204
+ # aligned without having to compute each row's exact glyph width.
205
+ DESC_INDENT = " "
206
+
207
+ def _build_list_body(self, width: int) -> tuple[list[str], list[str]]:
208
+ inner: list[str] = []
209
+ desc_width = max(width - len(self.DESC_INDENT), 10)
141
210
 
142
211
  for i in range(self._row_count):
143
212
  is_freeform_row = i == self._freeform_index
144
213
  title = FREEFORM_LABEL if is_freeform_row else self._options[i].title
145
214
  desc = "" if is_freeform_row else (self._options[i].description or "")
146
215
  is_cursor = i == self._cursor
147
- cursor_mark = "" if is_cursor else " "
148
-
149
- if self._allow_multiple and not is_freeform_row:
150
- # Same tick glyphs as the /extensions config panel. Cursor rows
151
- # get wrapped in reverse-video below, so leave them uncolored
152
- # there an embedded reset would cut the highlight short.
216
+ cursor_mark = "" if is_cursor else " "
217
+
218
+ if is_freeform_row:
219
+ # Synthetic action row, not a countable option keeps its own
220
+ # "❯" marker instead of a number.
221
+ marker = " "
222
+ elif self._allow_multiple:
223
+ # Same tick glyphs as the /extensions config panel, paired with
224
+ # the option's ordinal number. Cursor rows get wrapped in
225
+ # reverse-video below, so leave them uncolored here — an
226
+ # embedded reset would cut the highlight short.
153
227
  if i in self._checked:
154
228
  box = "✔" if is_cursor else "\x1b[32m✔\x1b[0m"
155
229
  else:
156
230
  box = "✖" if is_cursor else "\x1b[2m✖\x1b[0m"
157
- elif not is_freeform_row:
158
- # Radio-style circles: filled at the cursor position, hollow
159
- # elsewhere. Same reverse-video caveat as the checkbox ticks
160
- # above — leave the cursor row's glyph uncolored.
161
- box = "●" if is_cursor else "\x1b[2m○\x1b[0m"
231
+ marker = f"{i + 1}. {box}"
162
232
  else:
163
- box = " > "
233
+ marker = f"{i + 1}."
164
234
 
165
- row = f" {cursor_mark} {box} {title}"
235
+ row = f" {cursor_mark} {marker} {title}"
166
236
  if is_cursor:
167
237
  row = f"\x1b[7m{row}\x1b[0m"
168
- if desc:
169
- row += f" \x1b[2m{desc}\x1b[0m"
170
238
  inner.append(row)
171
239
 
172
- inner.append("")
240
+ # Description on its own hanging-indented line(s) below the title,
241
+ # not packed onto the title row — at left-column widths that
242
+ # would run straight into the next option's row.
243
+ for line in textwrap.wrap(desc, desc_width) if desc else []:
244
+ inner.append(f"{self.DESC_INDENT}\x1b[2m{line}\x1b[0m")
245
+
173
246
  hints = ["↑/↓ move", "Enter confirm", "Esc cancel"]
174
247
  if self._allow_multiple:
175
248
  hints.insert(1, "Space toggle")
176
- inner.append(" \x1b[2m" + " · ".join(hints) + "\x1b[0m")
177
- return _plain(inner)
249
+ footer = ["", " \x1b[2m" + " · ".join(hints) + "\x1b[0m"]
250
+ return inner, footer
251
+
252
+ @staticmethod
253
+ def _build_preview_box(preview: str | None, width: int, height: int) -> list[str]:
254
+ """A bordered box of exactly ``height`` lines, sized to ``width``.
255
+
256
+ Content beyond the available rows is truncated with a "N lines hidden"
257
+ footer rather than growing the box — the box height is pinned to the
258
+ paired option list so the two columns stay aligned row-for-row.
259
+ """
260
+ dim, reset = "\x1b[2m", "\x1b[0m"
261
+ inner_width = max(width - 4, 4)
262
+ top = f"{dim}┌{'─' * (width - 2)}┐{reset}"
263
+ bottom = f"{dim}└{'─' * (width - 2)}┘{reset}"
264
+ content_rows = max(height - 2, 1)
265
+
266
+ def pad(text: str) -> str:
267
+ return text + " " * max(0, inner_width - len(text))
268
+
269
+ def framed(text: str) -> str:
270
+ return f"{dim}│{reset} {pad(text)} {dim}│{reset}"
271
+
272
+ if not preview:
273
+ body = [framed("(no preview for this option)" if content_rows else "")]
274
+ body += [framed("") for _ in range(content_rows - len(body))]
275
+ return [top, *body[:content_rows], bottom]
276
+
277
+ import textwrap
278
+
279
+ wrapped: list[str] = []
280
+ for src_line in preview.splitlines() or [""]:
281
+ wrapped.extend(textwrap.wrap(src_line, inner_width) or [""])
282
+
283
+ if len(wrapped) > content_rows:
284
+ visible = wrapped[: max(content_rows - 1, 1)]
285
+ hidden = len(wrapped) - len(visible)
286
+ footer = f"✂ {hidden} lines hidden".center(inner_width)
287
+ body = [framed(line) for line in visible] + [framed(footer)]
288
+ else:
289
+ body = [framed(line) for line in wrapped]
290
+ body += [framed("") for _ in range(content_rows - len(body))]
291
+
292
+ return [top, *body[:content_rows], bottom]
178
293
 
179
294
  # ── Input ─────────────────────────────────────────────────────────────
180
295
 
@@ -0,0 +1,142 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ MAX_QUESTIONS = 4
6
+ MIN_OPTIONS = 2
7
+ MAX_OPTIONS = 4
8
+ MAX_LABEL_LENGTH = 60
9
+
10
+ FREEFORM_LABEL = "Type something…"
11
+
12
+
13
+ class AskUserOption(BaseModel):
14
+ title: str
15
+ description: str | None = None
16
+ preview: str | None = Field(
17
+ default=None,
18
+ description=(
19
+ "Optional preview content shown when this option is focused — an ASCII "
20
+ "mockup, code snippet, diagram, or config example the user needs to see "
21
+ "to compare choices. Markdown/plain text, multi-line supported. Only "
22
+ "supported on single-select questions (allow_multiple=False)."
23
+ ),
24
+ )
25
+
26
+
27
+ class AskUserQuestion(BaseModel):
28
+ question: str = Field(..., description="The question to ask the user")
29
+ context: str | None = Field(
30
+ default=None, description="Relevant context summary shown before the question"
31
+ )
32
+ options: list[str | AskUserOption] | None = Field(
33
+ default=None,
34
+ description=(
35
+ f"Multiple-choice options ({MIN_OPTIONS}-{MAX_OPTIONS} when provided). "
36
+ "Each needs a concise title (1-5 words); a description explaining the "
37
+ "trade-off is recommended. Do not author a 'Type something…' option "
38
+ "yourself — it is appended automatically when allow_freeform is true. "
39
+ "If you recommend a specific option, list it first and append "
40
+ '"(Recommended)" to its title.'
41
+ ),
42
+ )
43
+ allow_multiple: bool = Field(default=False, description="Allow selecting more than one option")
44
+ allow_freeform: bool = Field(
45
+ default=True, description="Offer a 'Type something' freeform option"
46
+ )
47
+ multiline: bool = Field(
48
+ default=False,
49
+ description=(
50
+ "Use a multi-line text editor for the freeform answer instead of a single "
51
+ "line — set this for open-ended, long-form answers (e.g. 'write your bio', "
52
+ "'describe the requirements'). Supports arrow-key navigation between lines, "
53
+ "Enter for a newline, Ctrl+S/Ctrl+Enter to submit."
54
+ ),
55
+ )
56
+
57
+
58
+ class AskUserParams(BaseModel):
59
+ questions: list[AskUserQuestion] = Field(
60
+ ...,
61
+ min_length=1,
62
+ max_length=MAX_QUESTIONS,
63
+ description=(
64
+ f"One or more questions to ask, in order (max {MAX_QUESTIONS} per call — "
65
+ "group all clarifying questions into one invocation instead of stacking "
66
+ "several ask_user calls back-to-back). Each is shown and answered before "
67
+ "the next appears — like a short interview. Use a single-item list for a "
68
+ "standalone question."
69
+ ),
70
+ )
71
+ timeout: int | None = Field(
72
+ default=None,
73
+ description=(
74
+ "Auto-dismiss after N ms of inactivity on the current question and "
75
+ "cancel the rest of the sequence if it times out"
76
+ ),
77
+ )
78
+
79
+
80
+ AskUserQuestion.model_rebuild()
81
+ AskUserParams.model_rebuild()
82
+
83
+
84
+ class QuestionValidationError(Exception):
85
+ """Raised when a question sequence fails validation before any UI is shown."""
86
+
87
+
88
+ def normalize_options(raw: list[str | AskUserOption] | None) -> list[AskUserOption]:
89
+ return [AskUserOption(title=o) if isinstance(o, str) else o for o in (raw or [])]
90
+
91
+
92
+ def validate_questions(questions: list[AskUserQuestion]) -> None:
93
+ """Reject malformed questionnaires up front, before rendering any UI.
94
+
95
+ Mirrors the guardrails of the reference ask-user-question implementation:
96
+ bounded option counts, no reserved/duplicate labels, no duplicate questions,
97
+ and previews restricted to single-select.
98
+ """
99
+ if len(questions) > MAX_QUESTIONS:
100
+ raise QuestionValidationError(
101
+ f"ask_user supports at most {MAX_QUESTIONS} questions per call; got "
102
+ f"{len(questions)}. Group them into fewer, related questions."
103
+ )
104
+
105
+ seen_questions: set[str] = set()
106
+ for q in questions:
107
+ if q.question in seen_questions:
108
+ raise QuestionValidationError(f"Duplicate question: {q.question!r}")
109
+ seen_questions.add(q.question)
110
+
111
+ if not q.options:
112
+ continue
113
+
114
+ if not (MIN_OPTIONS <= len(q.options) <= MAX_OPTIONS):
115
+ raise QuestionValidationError(
116
+ f"Question {q.question!r} must have between {MIN_OPTIONS} and "
117
+ f"{MAX_OPTIONS} options when options are provided; got {len(q.options)}."
118
+ )
119
+
120
+ seen_titles: set[str] = set()
121
+ for opt in q.options:
122
+ title = opt if isinstance(opt, str) else opt.title
123
+ preview = None if isinstance(opt, str) else opt.preview
124
+
125
+ if len(title) > MAX_LABEL_LENGTH:
126
+ raise QuestionValidationError(
127
+ f"Option title {title!r} exceeds {MAX_LABEL_LENGTH} characters."
128
+ )
129
+ if title == FREEFORM_LABEL:
130
+ raise QuestionValidationError(
131
+ f"{FREEFORM_LABEL!r} is reserved for the auto-appended freeform "
132
+ "row — do not author it as an option."
133
+ )
134
+ if title in seen_titles:
135
+ raise QuestionValidationError(f"Duplicate option title: {title!r}")
136
+ seen_titles.add(title)
137
+
138
+ if preview and q.allow_multiple:
139
+ raise QuestionValidationError(
140
+ "Option preview is only supported on single-select questions "
141
+ f"(question {q.question!r} has allow_multiple=True)."
142
+ )
@@ -0,0 +1,181 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from typing import Any
5
+
6
+ from component import _AskUserComponent # type: ignore[import-not-found]
7
+ from schema import ( # type: ignore[import-not-found]
8
+ AskUserParams,
9
+ QuestionValidationError,
10
+ normalize_options,
11
+ validate_questions,
12
+ )
13
+
14
+ from tau.tool.render import call_line
15
+ from tau.tool.types import (
16
+ Tool,
17
+ ToolContext,
18
+ ToolExecutionMode,
19
+ ToolInvocation,
20
+ ToolKind,
21
+ ToolResult,
22
+ )
23
+
24
+
25
+ def _render_call(args: dict, _streaming: bool = False) -> list[str]:
26
+ questions = args.get("questions") or []
27
+ if len(questions) <= 1:
28
+ label = questions[0].get("question", "") if questions else ""
29
+ else:
30
+ label = f"{len(questions)} questions"
31
+ return call_line("ask_user", label)
32
+
33
+
34
+ def _render_result(content: str, opts: Any) -> list[str]:
35
+ return content.splitlines() or [content]
36
+
37
+
38
+ class AskUserTool(Tool):
39
+ def __init__(self, runtime_ref: Any) -> None:
40
+ self._runtime_ref = runtime_ref
41
+ super().__init__(
42
+ name="ask_user",
43
+ description=(
44
+ "Ask the human one or more focused questions and wait for their decision "
45
+ "before proceeding. Pass multiple questions to run them as a sequence — "
46
+ "each is shown and answered in turn, like a short interview — instead of "
47
+ "issuing separate calls. Do not stack multiple ask_user calls back-to-back; "
48
+ "group all clarifying questions into one invocation. Use for high-impact "
49
+ "architectural trade-offs, ambiguous or conflicting requirements, or "
50
+ "assumptions that would materially change the implementation. Each "
51
+ "question supports single-select, multi-select, and freeform text "
52
+ "answers, and up to 4 options when options are given. If you recommend a "
53
+ "specific option, list it first and append \"(Recommended)\" to its "
54
+ "title. Only available in an interactive TUI session."
55
+ ),
56
+ schema=AskUserParams,
57
+ kind=ToolKind.Read,
58
+ execution_mode=ToolExecutionMode.Sequential,
59
+ render_call=_render_call,
60
+ render_result=_render_result,
61
+ render_shell="default",
62
+ )
63
+
64
+ async def execute(
65
+ self,
66
+ invocation: ToolInvocation,
67
+ tool_execution_update_callback=None,
68
+ signal=None,
69
+ context: ToolContext | None = None,
70
+ ) -> ToolResult:
71
+ params = AskUserParams.model_validate(invocation.params)
72
+
73
+ try:
74
+ validate_questions(params.questions)
75
+ except QuestionValidationError as e:
76
+ return ToolResult.error(invocation.id, str(e))
77
+
78
+ runtime = self._runtime_ref.runtime if self._runtime_ref is not None else None
79
+ if runtime is None:
80
+ return ToolResult.error(invocation.id, "ask_user unavailable: runtime not ready")
81
+
82
+ from tau.extensions.context import ExtensionContext
83
+
84
+ ext_ctx = ExtensionContext.from_runtime(runtime)
85
+ ui = ext_ctx.ui
86
+ if ui is None:
87
+ return ToolResult.error(
88
+ invocation.id,
89
+ "ask_user requires an interactive TUI session and is "
90
+ "unavailable in headless/RPC mode",
91
+ )
92
+
93
+ answers: list[dict] = []
94
+
95
+ for question in params.questions:
96
+ options = normalize_options(question.options)
97
+ response = await self._ask_one(ui, question, options, params.timeout)
98
+
99
+ if response is None:
100
+ return ToolResult.ok(
101
+ invocation.id,
102
+ self._format_answers(answers, cancelled_at=question.question),
103
+ metadata={
104
+ "cancelled": True,
105
+ "answers": answers,
106
+ "cancelled_question": question.question,
107
+ },
108
+ )
109
+
110
+ if response["kind"] == "freeform":
111
+ content = response["text"]
112
+ else:
113
+ content = ", ".join(response["selections"])
114
+
115
+ answers.append(
116
+ {"question": question.question, "response": content, "raw": response}
117
+ )
118
+
119
+ return ToolResult.ok(
120
+ invocation.id,
121
+ self._format_answers(answers),
122
+ metadata={"cancelled": False, "answers": answers},
123
+ )
124
+
125
+ async def _ask_one(
126
+ self,
127
+ ui: Any,
128
+ question: Any,
129
+ options: Any,
130
+ timeout: int | None,
131
+ ) -> dict | None:
132
+ loop = asyncio.get_running_loop()
133
+ fut: asyncio.Future[dict | None] = loop.create_future()
134
+ timeout_task_ref: list[asyncio.Task | None] = [None]
135
+
136
+ def _on_done(value: dict | None) -> None:
137
+ t = timeout_task_ref[0]
138
+ if t is not None and not t.done():
139
+ t.cancel()
140
+ if not fut.done():
141
+ fut.set_result(value)
142
+
143
+ def _factory(_tui, _theme, _kb, done):
144
+ component = _AskUserComponent(
145
+ question=question.question,
146
+ context=question.context,
147
+ options=options,
148
+ allow_multiple=question.allow_multiple,
149
+ allow_freeform=question.allow_freeform,
150
+ multiline=question.multiline,
151
+ on_done=lambda v: (_on_done(v), done(v)),
152
+ )
153
+ if timeout:
154
+ timeout_ms = timeout
155
+
156
+ async def _auto_dismiss() -> None:
157
+ await asyncio.sleep(timeout_ms / 1000)
158
+ _on_done(None)
159
+ done(None)
160
+
161
+ timeout_task_ref[0] = asyncio.ensure_future(_auto_dismiss())
162
+ return component
163
+
164
+ await ui.custom_inline(_factory, kind="ask_user")
165
+ return await fut
166
+
167
+ @staticmethod
168
+ def _format_answers(answers: list[dict], cancelled_at: str | None = None) -> str:
169
+ if not answers and cancelled_at is None:
170
+ return "The user cancelled the question without answering."
171
+
172
+ lines: list[str] = []
173
+ for i, item in enumerate(answers, start=1):
174
+ lines.append(f"Q{i}: {item['question']}")
175
+ lines.append(f"A{i}: {item['response']}")
176
+ lines.append("")
177
+
178
+ if cancelled_at is not None:
179
+ lines.append(f"(Cancelled before answering: {cancelled_at})")
180
+
181
+ return "\n".join(lines).rstrip()