klaude-code 1.2.18__tar.gz → 1.2.19__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 (196) hide show
  1. {klaude_code-1.2.18 → klaude_code-1.2.19}/PKG-INFO +17 -2
  2. {klaude_code-1.2.18 → klaude_code-1.2.19}/README.md +16 -1
  3. {klaude_code-1.2.18 → klaude_code-1.2.19}/pyproject.toml +1 -1
  4. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/main.py +42 -22
  5. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/runtime.py +41 -2
  6. klaude_code-1.2.18/src/klaude_code/version.py → klaude_code-1.2.19/src/klaude_code/cli/self_update.py +110 -2
  7. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/export_online_cmd.py +8 -3
  8. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/registry.py +67 -22
  9. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/thinking_cmd.py +4 -3
  10. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/executor.py +21 -1
  11. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-sub-agent-explore.md +14 -2
  12. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/task.py +9 -7
  13. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/read_tool.md +1 -1
  14. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/read_tool.py +3 -2
  15. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/memory/skill_loader.py +12 -10
  16. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/tool_registry.py +1 -1
  17. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/anthropic/client.py +25 -9
  18. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openai_compatible/client.py +5 -2
  19. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openrouter/client.py +7 -3
  20. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/responses/client.py +6 -1
  21. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/session/session.py +33 -13
  22. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/session/templates/export_session.html +43 -41
  23. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/completers.py +212 -71
  24. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/input_prompt_toolkit.py +1 -1
  25. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/renderer.py +2 -2
  26. klaude_code-1.2.19/src/klaude_code/ui/renderers/common.py +62 -0
  27. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/developer.py +2 -3
  28. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/errors.py +1 -1
  29. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/metadata.py +10 -1
  30. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/tools.py +3 -4
  31. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/utils/common.py +0 -18
  32. klaude_code-1.2.18/src/klaude_code/ui/renderers/common.py +0 -8
  33. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/__init__.py +0 -0
  34. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/auth/__init__.py +0 -0
  35. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/auth/codex/__init__.py +0 -0
  36. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/auth/codex/exceptions.py +0 -0
  37. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
  38. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/auth/codex/oauth.py +0 -0
  39. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/auth/codex/token_manager.py +0 -0
  40. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/__init__.py +0 -0
  41. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/auth_cmd.py +0 -0
  42. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/config_cmd.py +0 -0
  43. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/debug.py +0 -0
  44. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/list_model.py +0 -0
  45. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/session_cmd.py +0 -0
  46. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/__init__.py +0 -0
  47. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/clear_cmd.py +0 -0
  48. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/command_abc.py +0 -0
  49. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/debug_cmd.py +0 -0
  50. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/diff_cmd.py +0 -0
  51. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/export_cmd.py +0 -0
  52. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/help_cmd.py +0 -0
  53. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/model_cmd.py +0 -0
  54. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/prompt-deslop.md +0 -0
  55. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/prompt-dev-docs-update.md +0 -0
  56. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/prompt-dev-docs.md +0 -0
  57. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/prompt-handoff.md +0 -0
  58. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/prompt-init.md +0 -0
  59. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/prompt_command.py +0 -0
  60. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/refresh_cmd.py +0 -0
  61. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/release_notes_cmd.py +0 -0
  62. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/status_cmd.py +0 -0
  63. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/terminal_setup_cmd.py +0 -0
  64. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/config/__init__.py +0 -0
  65. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/config/config.py +0 -0
  66. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/config/select_model.py +0 -0
  67. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/const/__init__.py +0 -0
  68. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/__init__.py +0 -0
  69. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/agent.py +0 -0
  70. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/manager/__init__.py +0 -0
  71. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/manager/llm_clients.py +0 -0
  72. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/manager/llm_clients_builder.py +0 -0
  73. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/manager/sub_agent_manager.py +0 -0
  74. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompt.py +0 -0
  75. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-claude-code.md +0 -0
  76. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +0 -0
  77. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1.md +0 -0
  78. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-gemini.md +0 -0
  79. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-minimal.md +0 -0
  80. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-sub-agent-oracle.md +0 -0
  81. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-sub-agent-web.md +0 -0
  82. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-sub-agent.md +0 -0
  83. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/reminders.py +0 -0
  84. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/__init__.py +0 -0
  85. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/__init__.py +0 -0
  86. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/_utils.py +0 -0
  87. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/apply_patch.py +0 -0
  88. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
  89. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/apply_patch_tool.py +0 -0
  90. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
  91. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/edit_tool.py +0 -0
  92. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/multi_edit_tool.md +0 -0
  93. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/multi_edit_tool.py +0 -0
  94. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/write_tool.md +0 -0
  95. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/write_tool.py +0 -0
  96. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/memory/__init__.py +0 -0
  97. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/memory/memory_tool.md +0 -0
  98. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/memory/memory_tool.py +0 -0
  99. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/memory/skill_tool.md +0 -0
  100. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/memory/skill_tool.py +0 -0
  101. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/report_back_tool.py +0 -0
  102. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/shell/__init__.py +0 -0
  103. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
  104. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/shell/bash_tool.py +0 -0
  105. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/shell/command_safety.py +0 -0
  106. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/sub_agent_tool.py +0 -0
  107. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/todo/__init__.py +0 -0
  108. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
  109. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/todo/todo_write_tool.py +0 -0
  110. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
  111. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
  112. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
  113. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/tool_abc.py +0 -0
  114. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/tool_context.py +0 -0
  115. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/tool_runner.py +0 -0
  116. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/truncation.py +0 -0
  117. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/__init__.py +0 -0
  118. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/mermaid_tool.md +0 -0
  119. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/mermaid_tool.py +0 -0
  120. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/web_fetch_tool.md +0 -0
  121. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/web_fetch_tool.py +0 -0
  122. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/web_search_tool.md +0 -0
  123. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/web_search_tool.py +0 -0
  124. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/turn.py +0 -0
  125. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/__init__.py +0 -0
  126. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/anthropic/__init__.py +0 -0
  127. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/anthropic/input.py +0 -0
  128. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/client.py +0 -0
  129. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/codex/__init__.py +0 -0
  130. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/codex/client.py +0 -0
  131. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/input_common.py +0 -0
  132. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
  133. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openai_compatible/input.py +0 -0
  134. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openai_compatible/stream_processor.py +0 -0
  135. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -0
  136. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openrouter/__init__.py +0 -0
  137. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openrouter/input.py +0 -0
  138. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openrouter/reasoning_handler.py +0 -0
  139. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/registry.py +0 -0
  140. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/responses/__init__.py +0 -0
  141. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/responses/input.py +0 -0
  142. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/usage.py +0 -0
  143. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/__init__.py +0 -0
  144. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/commands.py +0 -0
  145. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/events.py +0 -0
  146. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/llm_param.py +0 -0
  147. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/model.py +0 -0
  148. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/op.py +0 -0
  149. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/op_handler.py +0 -0
  150. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/sub_agent/__init__.py +0 -0
  151. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/sub_agent/explore.py +0 -0
  152. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/sub_agent/oracle.py +0 -0
  153. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/sub_agent/task.py +0 -0
  154. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/sub_agent/web.py +0 -0
  155. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/tools.py +0 -0
  156. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/session/__init__.py +0 -0
  157. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/session/export.py +0 -0
  158. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/session/selector.py +0 -0
  159. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/trace/__init__.py +0 -0
  160. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/trace/log.py +0 -0
  161. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/__init__.py +0 -0
  162. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/core/__init__.py +0 -0
  163. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/core/display.py +0 -0
  164. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/core/input.py +0 -0
  165. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/core/stage_manager.py +0 -0
  166. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/__init__.py +0 -0
  167. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/debug/__init__.py +0 -0
  168. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/debug/display.py +0 -0
  169. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/exec/__init__.py +0 -0
  170. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/exec/display.py +0 -0
  171. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/__init__.py +0 -0
  172. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/clipboard.py +0 -0
  173. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/display.py +0 -0
  174. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/event_handler.py +0 -0
  175. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/key_bindings.py +0 -0
  176. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/__init__.py +0 -0
  177. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/assistant.py +0 -0
  178. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/diffs.py +0 -0
  179. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/sub_agent.py +0 -0
  180. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/thinking.py +0 -0
  181. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/user_input.py +0 -0
  182. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/__init__.py +0 -0
  183. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/code_panel.py +0 -0
  184. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/live.py +0 -0
  185. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/markdown.py +0 -0
  186. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/quote.py +0 -0
  187. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/searchable_text.py +0 -0
  188. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/status.py +0 -0
  189. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/theme.py +0 -0
  190. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/terminal/__init__.py +0 -0
  191. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/terminal/color.py +0 -0
  192. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/terminal/control.py +0 -0
  193. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/terminal/notifier.py +0 -0
  194. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/terminal/progress_bar.py +0 -0
  195. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/utils/__init__.py +0 -0
  196. {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/utils/debouncer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 1.2.18
3
+ Version: 1.2.19
4
4
  Summary: Add your description here
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: ddgs>=9.9.3
@@ -41,6 +41,21 @@ To update:
41
41
  uv tool upgrade klaude-code
42
42
  ```
43
43
 
44
+ Or use the built-in alias command:
45
+
46
+ ```bash
47
+ klaude update
48
+ klaude upgrade
49
+ ```
50
+
51
+ To show version:
52
+
53
+ ```bash
54
+ klaude --version
55
+ klaude -v
56
+ klaude version
57
+ ```
58
+
44
59
  ## Usage
45
60
 
46
61
  ### Interactive Mode
@@ -50,7 +65,7 @@ klaude [--model <name>] [--select-model]
50
65
  ```
51
66
 
52
67
  **Options:**
53
- - `--version`/`-V`: Show version and exit.
68
+ - `--version`/`-V`/`-v`: Show version and exit.
54
69
  - `--model`/`-m`: Preferred model name (exact match picks immediately; otherwise opens the interactive selector filtered by this value).
55
70
  - `--select-model`/`-s`: Open the interactive model selector at startup (shows all models unless `--model` is also provided).
56
71
  - `--continue`/`-c`: Resume the most recent session.
@@ -23,6 +23,21 @@ To update:
23
23
  uv tool upgrade klaude-code
24
24
  ```
25
25
 
26
+ Or use the built-in alias command:
27
+
28
+ ```bash
29
+ klaude update
30
+ klaude upgrade
31
+ ```
32
+
33
+ To show version:
34
+
35
+ ```bash
36
+ klaude --version
37
+ klaude -v
38
+ klaude version
39
+ ```
40
+
26
41
  ## Usage
27
42
 
28
43
  ### Interactive Mode
@@ -32,7 +47,7 @@ klaude [--model <name>] [--select-model]
32
47
  ```
33
48
 
34
49
  **Options:**
35
- - `--version`/`-V`: Show version and exit.
50
+ - `--version`/`-V`/`-v`: Show version and exit.
36
51
  - `--model`/`-m`: Preferred model name (exact match picks immediately; otherwise opens the interactive selector filtered by this value).
37
52
  - `--select-model`/`-s`: Open the interactive model selector at startup (shows all models unless `--model` is also provided).
38
53
  - `--continue`/`-c`: Resume the most recent session.
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "klaude-code"
7
- version = "1.2.18"
7
+ version = "1.2.19"
8
8
  description = "Add your description here"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -1,8 +1,6 @@
1
1
  import asyncio
2
2
  import os
3
3
  import sys
4
- from importlib.metadata import PackageNotFoundError
5
- from importlib.metadata import version as pkg_version
6
4
  from pathlib import Path
7
5
 
8
6
  import typer
@@ -10,6 +8,7 @@ import typer
10
8
  from klaude_code.cli.auth_cmd import register_auth_commands
11
9
  from klaude_code.cli.config_cmd import register_config_commands
12
10
  from klaude_code.cli.debug import DEBUG_FILTER_HELP, open_log_file_in_editor, resolve_debug_settings
11
+ from klaude_code.cli.self_update import register_self_update_commands, version_option_callback
13
12
  from klaude_code.cli.session_cmd import register_session_commands
14
13
  from klaude_code.session import Session, resume_select_session
15
14
  from klaude_code.trace import DebugType, prepare_debug_log_file
@@ -21,10 +20,13 @@ def set_terminal_title(title: str) -> None:
21
20
  sys.stdout.flush()
22
21
 
23
22
 
24
- def setup_terminal_title() -> None:
25
- """Set terminal title to current folder name."""
23
+ def update_terminal_title(model_name: str | None = None) -> None:
24
+ """Update terminal title with folder name and optional model name."""
26
25
  folder_name = os.path.basename(os.getcwd())
27
- set_terminal_title(f"{folder_name}: klaude")
26
+ if model_name:
27
+ set_terminal_title(f"{folder_name}: klaude ✳ {model_name}")
28
+ else:
29
+ set_terminal_title(f"{folder_name}: klaude")
28
30
 
29
31
 
30
32
  def prepare_debug_logging(debug: bool, debug_filter: str | None) -> tuple[bool, set[DebugType] | None, Path | None]:
@@ -78,20 +80,6 @@ def read_input_content(cli_argument: str) -> str | None:
78
80
  return content
79
81
 
80
82
 
81
- def _version_callback(value: bool) -> None:
82
- """Show version and exit."""
83
- if value:
84
- try:
85
- ver = pkg_version("klaude-code")
86
- except PackageNotFoundError:
87
- # Package is not installed or has no metadata; show a generic version string.
88
- ver = "unknown"
89
- except Exception:
90
- ver = "unknown"
91
- print(f"klaude-code {ver}")
92
- raise typer.Exit(0)
93
-
94
-
95
83
  app = typer.Typer(
96
84
  add_completion=False,
97
85
  pretty_exceptions_enable=False,
@@ -103,6 +91,8 @@ register_session_commands(app)
103
91
  register_auth_commands(app)
104
92
  register_config_commands(app)
105
93
 
94
+ register_self_update_commands(app)
95
+
106
96
 
107
97
  @app.command("exec")
108
98
  def exec_command(
@@ -146,7 +136,7 @@ def exec_command(
146
136
  ),
147
137
  ) -> None:
148
138
  """Execute non-interactively with provided input."""
149
- setup_terminal_title()
139
+ update_terminal_title()
150
140
 
151
141
  merged_input = read_input_content(input_content)
152
142
  if merged_input is None:
@@ -190,8 +180,9 @@ def main_callback(
190
180
  False,
191
181
  "--version",
192
182
  "-V",
183
+ "-v",
193
184
  help="Show version and exit",
194
- callback=_version_callback,
185
+ callback=version_option_callback,
195
186
  is_eager=True,
196
187
  ),
197
188
  model: str | None = typer.Option(
@@ -234,7 +225,7 @@ def main_callback(
234
225
  from klaude_code.cli.runtime import AppInitConfig, run_interactive
235
226
  from klaude_code.config.select_model import select_model_from_config
236
227
 
237
- setup_terminal_title()
228
+ update_terminal_title()
238
229
 
239
230
  chosen_model = model
240
231
  if model or select_model:
@@ -254,6 +245,35 @@ def main_callback(
254
245
  session_id = Session.most_recent_session_id()
255
246
  # If still no session_id, leave as None to create a new session
256
247
 
248
+ if session_id is not None and chosen_model is None:
249
+ from klaude_code.config import load_config
250
+ from klaude_code.trace import log
251
+
252
+ session_meta = Session.load_meta(session_id)
253
+ cfg = load_config()
254
+
255
+ if cfg is not None and session_meta.model_config_name:
256
+ if any(m.model_name == session_meta.model_config_name for m in cfg.model_list):
257
+ chosen_model = session_meta.model_config_name
258
+ else:
259
+ log(
260
+ (
261
+ f"Warning: session model '{session_meta.model_config_name}' is not defined in config; falling back to default",
262
+ "yellow",
263
+ )
264
+ )
265
+
266
+ if cfg is not None and chosen_model is None and session_meta.model_name:
267
+ raw_model = session_meta.model_name.strip()
268
+ if raw_model:
269
+ matches = [
270
+ m.model_name
271
+ for m in cfg.model_list
272
+ if (m.model_params.model or "").strip().lower() == raw_model.lower()
273
+ ]
274
+ if len(matches) == 1:
275
+ chosen_model = matches[0]
276
+
257
277
  debug_enabled, debug_filters, log_path = prepare_debug_logging(debug, debug_filter)
258
278
 
259
279
  init_config = AppInitConfig(
@@ -8,9 +8,11 @@ import typer
8
8
  from rich.text import Text
9
9
 
10
10
  from klaude_code import ui
11
+ from klaude_code.cli.main import update_terminal_title
12
+ from klaude_code.cli.self_update import get_update_message
11
13
  from klaude_code.command import has_interactive_command
12
14
  from klaude_code.config import Config, load_config
13
- from klaude_code.core.agent import DefaultModelProfileProvider, VanillaModelProfileProvider
15
+ from klaude_code.core.agent import Agent, DefaultModelProfileProvider, VanillaModelProfileProvider
14
16
  from klaude_code.core.executor import Executor
15
17
  from klaude_code.core.manager import build_llm_clients
16
18
  from klaude_code.protocol import events, op
@@ -21,7 +23,6 @@ from klaude_code.ui.modes.repl.input_prompt_toolkit import REPLStatusSnapshot
21
23
  from klaude_code.ui.terminal.color import is_light_terminal_background
22
24
  from klaude_code.ui.terminal.control import install_sigint_double_press_exit, start_esc_interrupt_monitor
23
25
  from klaude_code.ui.terminal.progress_bar import OSC94States, emit_osc94
24
- from klaude_code.version import get_update_message
25
26
 
26
27
 
27
28
  class PrintCapable(Protocol):
@@ -92,8 +93,12 @@ async def initialize_app_components(init_config: AppInitConfig) -> AppComponents
92
93
  event_queue,
93
94
  llm_clients,
94
95
  model_profile_provider=model_profile_provider,
96
+ on_model_change=update_terminal_title,
95
97
  )
96
98
 
99
+ # Update terminal title with initial model name
100
+ update_terminal_title(llm_clients.main.model_name)
101
+
97
102
  # Start executor in background
98
103
  executor_task = asyncio.create_task(executor.start())
99
104
 
@@ -151,6 +156,28 @@ async def initialize_session(
151
156
  return active_session_id or session_id
152
157
 
153
158
 
159
+ def _backfill_session_model_config(
160
+ agent: Agent | None,
161
+ model_override: str | None,
162
+ default_model: str,
163
+ is_new_session: bool,
164
+ ) -> None:
165
+ """Backfill model_config_name and model_thinking on newly created sessions."""
166
+ if agent is None or agent.session.model_config_name is not None:
167
+ return
168
+
169
+ if model_override is not None:
170
+ agent.session.model_config_name = model_override
171
+ elif is_new_session:
172
+ agent.session.model_config_name = default_model
173
+ else:
174
+ return
175
+
176
+ if agent.session.model_thinking is None and agent.profile:
177
+ agent.session.model_thinking = agent.profile.llm_client.get_llm_config().thinking
178
+ # Don't save here - session will be saved when first message is sent via append_history()
179
+
180
+
154
181
  async def cleanup_app_components(components: AppComponents) -> None:
155
182
  """Clean up all application components."""
156
183
  try:
@@ -192,6 +219,12 @@ async def run_exec(init_config: AppInitConfig, input_content: str) -> None:
192
219
 
193
220
  try:
194
221
  session_id = await initialize_session(components.executor, components.event_queue)
222
+ _backfill_session_model_config(
223
+ components.executor.context.current_agent,
224
+ init_config.model,
225
+ components.config.main_model,
226
+ is_new_session=True,
227
+ )
195
228
 
196
229
  # Submit the input content directly
197
230
  await components.executor.submit_and_wait(
@@ -260,6 +293,12 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
260
293
 
261
294
  try:
262
295
  await initialize_session(components.executor, components.event_queue, session_id=session_id)
296
+ _backfill_session_model_config(
297
+ components.executor.context.current_agent,
298
+ init_config.model,
299
+ components.config.main_model,
300
+ is_new_session=session_id is None,
301
+ )
263
302
 
264
303
  def _get_active_session_id() -> str | None:
265
304
  """Get the current active session ID dynamically.
@@ -1,4 +1,4 @@
1
- """Version checking utilities for klaude-code."""
1
+ """Self-update and version utilities for klaude-code."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -8,8 +8,14 @@ import subprocess
8
8
  import threading
9
9
  import time
10
10
  import urllib.request
11
+ from importlib.metadata import PackageNotFoundError
12
+ from importlib.metadata import version as pkg_version
11
13
  from typing import NamedTuple
12
14
 
15
+ import typer
16
+
17
+ from klaude_code.trace import log
18
+
13
19
  PACKAGE_NAME = "klaude-code"
14
20
  PYPI_URL = f"https://pypi.org/pypi/{PACKAGE_NAME}/json"
15
21
  CHECK_INTERVAL_SECONDS = 3600 # Check at most once per hour
@@ -160,4 +166,106 @@ def get_update_message() -> str | None:
160
166
  info = check_for_updates()
161
167
  if info is None or not info.update_available:
162
168
  return None
163
- return f"New version available: {info.latest}. Please run `uv tool upgrade {PACKAGE_NAME}` to upgrade."
169
+ return f"New version available: {info.latest}. Please run `klaude upgrade` to upgrade."
170
+
171
+
172
+ def _print_version() -> None:
173
+ try:
174
+ ver = pkg_version(PACKAGE_NAME)
175
+ except PackageNotFoundError:
176
+ ver = "unknown"
177
+ except Exception:
178
+ ver = "unknown"
179
+ print(f"{PACKAGE_NAME} {ver}")
180
+
181
+
182
+ def version_option_callback(value: bool) -> None:
183
+ """Show version and exit."""
184
+ if value:
185
+ _print_version()
186
+ raise typer.Exit(0)
187
+
188
+
189
+ def version_command() -> None:
190
+ """Show version and exit."""
191
+
192
+ _print_version()
193
+
194
+
195
+ def update_command(
196
+ check: bool = typer.Option(
197
+ False,
198
+ "--check",
199
+ help="Check for updates and exit without upgrading",
200
+ ),
201
+ ) -> None:
202
+ """Upgrade klaude-code when installed via `uv tool`."""
203
+
204
+ info = check_for_updates_blocking()
205
+
206
+ if check:
207
+ if info is None:
208
+ log(("Error: `uv` is not available; cannot check for updates.", "red"))
209
+ log(f"Install uv, then run `uv tool upgrade {PACKAGE_NAME}`.")
210
+ raise typer.Exit(1)
211
+
212
+ installed_display = info.installed or "unknown"
213
+ latest_display = info.latest or "unknown"
214
+ status = "update available" if info.update_available else "up to date"
215
+
216
+ log(f"{PACKAGE_NAME} installed: {installed_display}")
217
+ log(f"{PACKAGE_NAME} latest: {latest_display}")
218
+ log(f"Status: {status}")
219
+
220
+ if info.update_available:
221
+ log("Run `klaude upgrade` to upgrade.")
222
+
223
+ return
224
+
225
+ if shutil.which("uv") is None:
226
+ log(("Error: `uv` not found in PATH.", "red"))
227
+ log(f"To update, install uv and run `uv tool upgrade {PACKAGE_NAME}`.")
228
+ raise typer.Exit(1)
229
+
230
+ log(f"Running `uv tool upgrade {PACKAGE_NAME}`...")
231
+ result = subprocess.run(["uv", "tool", "upgrade", PACKAGE_NAME], check=False)
232
+ if result.returncode != 0:
233
+ log((f"Error: update failed (exit code {result.returncode}).", "red"))
234
+ raise typer.Exit(result.returncode or 1)
235
+
236
+ log("Update complete. Please re-run `klaude` to use the new version.")
237
+
238
+
239
+ def register_self_update_commands(app: typer.Typer) -> None:
240
+ """Register self-update and version subcommands to the given Typer app."""
241
+
242
+ app.command("update")(update_command)
243
+ app.command("upgrade", help="Alias for `klaude update`.")(update_command)
244
+ app.command("version", help="Alias for `klaude --version`.")(version_command)
245
+
246
+
247
+ def check_for_updates_blocking() -> VersionInfo | None:
248
+ """Check for updates to klaude-code synchronously.
249
+
250
+ This is intended for CLI commands (e.g. `klaude update --check`) that need
251
+ a deterministic result instead of the async cached behavior.
252
+
253
+ Returns:
254
+ VersionInfo if uv is available, otherwise None.
255
+ """
256
+
257
+ if not _has_uv():
258
+ return None
259
+
260
+ installed = _get_installed_version()
261
+ latest = _get_latest_version()
262
+
263
+ update_available = False
264
+ if installed and latest:
265
+ update_available = _compare_versions(installed, latest)
266
+
267
+ return VersionInfo(
268
+ installed=installed,
269
+ latest=latest,
270
+ update_available=update_available,
271
+ )
@@ -6,6 +6,9 @@ import subprocess
6
6
  import tempfile
7
7
  from pathlib import Path
8
8
 
9
+ from rich.console import Console
10
+ from rich.text import Text
11
+
9
12
  from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
10
13
  from klaude_code.protocol import commands, events, model
11
14
  from klaude_code.session.export import build_export_html
@@ -56,9 +59,11 @@ class ExportOnlineCommand(CommandABC):
56
59
  return CommandResult(events=[event])
57
60
 
58
61
  try:
59
- html_doc = self._build_html(agent)
60
- domain = self._generate_domain()
61
- url = self._deploy_to_surge(surge_cmd, html_doc, domain)
62
+ console = Console()
63
+ with console.status(Text("Deploying to surge.sh...", style="dim"), spinner_style="dim"):
64
+ html_doc = self._build_html(agent)
65
+ domain = self._generate_domain()
66
+ url = self._deploy_to_surge(surge_cmd, html_doc, domain)
62
67
 
63
68
  event = events.DeveloperMessageEvent(
64
69
  session_id=agent.session.id,
@@ -12,6 +12,68 @@ if TYPE_CHECKING:
12
12
  _COMMANDS: dict[commands.CommandName | str, "CommandABC"] = {}
13
13
 
14
14
 
15
+ def _command_key_to_str(key: commands.CommandName | str) -> str:
16
+ if isinstance(key, commands.CommandName):
17
+ return key.value
18
+ return key
19
+
20
+
21
+ def _resolve_command_key(command_name_raw: str) -> commands.CommandName | str | None:
22
+ """Resolve raw command token to a registered command key.
23
+
24
+ Resolution order:
25
+ 1) Exact match
26
+ 2) Enum conversion (for standard commands)
27
+ 3) Prefix match (supports abbreviations like `exp` -> `export`)
28
+
29
+ Prefix match rules:
30
+ - If there's exactly one prefix match, use it.
31
+ - If multiple matches exist and one command name is a prefix of all others,
32
+ treat it as the base command and use it (e.g. `export` over `export-online`).
33
+ - Otherwise, consider it ambiguous and return None.
34
+ """
35
+
36
+ if not command_name_raw:
37
+ return None
38
+
39
+ # Exact string match (works for both Enum and str keys because CommandName is a str Enum)
40
+ if command_name_raw in _COMMANDS:
41
+ return command_name_raw
42
+
43
+ # Enum conversion for standard commands
44
+ try:
45
+ enum_key = commands.CommandName(command_name_raw)
46
+ except ValueError:
47
+ enum_key = None
48
+ else:
49
+ if enum_key in _COMMANDS:
50
+ return enum_key
51
+
52
+ # Prefix match across all registered names
53
+ matching_keys: list[commands.CommandName | str] = []
54
+ matching_names: list[str] = []
55
+ for key in _COMMANDS:
56
+ key_str = _command_key_to_str(key)
57
+ if key_str.startswith(command_name_raw):
58
+ matching_keys.append(key)
59
+ matching_names.append(key_str)
60
+
61
+ if len(matching_keys) == 1:
62
+ return matching_keys[0]
63
+
64
+ if len(matching_keys) > 1:
65
+ # Prefer the base command when one is a prefix of all other matches.
66
+ base_matches = [
67
+ key
68
+ for key, key_name in zip(matching_keys, matching_names, strict=True)
69
+ if all(other.startswith(key_name) for other in matching_names if other != key_name)
70
+ ]
71
+ if len(base_matches) == 1:
72
+ return base_matches[0]
73
+
74
+ return None
75
+
76
+
15
77
  def register(cmd: "CommandABC") -> None:
16
78
  """Register a command instance. Order of registration determines display order."""
17
79
  _COMMANDS[cmd.name] = cmd
@@ -45,7 +107,7 @@ def get_commands() -> dict[commands.CommandName | str, "CommandABC"]:
45
107
 
46
108
  def is_slash_command_name(name: str) -> bool:
47
109
  _ensure_commands_loaded()
48
- return name in _COMMANDS
110
+ return _resolve_command_key(name) is not None
49
111
 
50
112
 
51
113
  async def dispatch_command(raw: str, agent: Agent) -> CommandResult:
@@ -58,21 +120,7 @@ async def dispatch_command(raw: str, agent: Agent) -> CommandResult:
58
120
  command_name_raw = splits[0][1:]
59
121
  rest = " ".join(splits[1:]) if len(splits) > 1 else ""
60
122
 
61
- # Try to match against registered commands (both Enum and string keys)
62
- command_key = None
63
-
64
- # First try exact string match
65
- if command_name_raw in _COMMANDS:
66
- command_key = command_name_raw
67
- else:
68
- # Then try Enum conversion for standard commands
69
- try:
70
- enum_key = commands.CommandName(command_name_raw)
71
- if enum_key in _COMMANDS:
72
- command_key = enum_key
73
- except ValueError:
74
- pass
75
-
123
+ command_key = _resolve_command_key(command_name_raw)
76
124
  if command_key is None:
77
125
  return CommandResult(actions=[InputAction.run_agent(raw)])
78
126
 
@@ -106,11 +154,8 @@ def has_interactive_command(raw: str) -> bool:
106
154
  return False
107
155
  splits = raw.split(" ", maxsplit=1)
108
156
  command_name_raw = splits[0][1:]
109
- try:
110
- command_name = commands.CommandName(command_name_raw)
111
- except ValueError:
112
- return False
113
- if command_name not in _COMMANDS:
157
+ command_key = _resolve_command_key(command_name_raw)
158
+ if command_key is None:
114
159
  return False
115
- command = _COMMANDS[command_name]
160
+ command = _COMMANDS[command_key]
116
161
  return command.is_interactive
@@ -6,9 +6,9 @@ from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
6
6
  from klaude_code.protocol import commands, events, llm_param, model
7
7
 
8
8
  # Thinking level options for different protocols
9
- RESPONSES_LEVELS = ["minimal", "low", "medium", "high"]
10
- RESPONSES_GPT51_LEVELS = ["none", "minimal", "low", "medium", "high"]
11
- RESPONSES_GPT52_LEVELS = ["none", "minimal", "low", "medium", "high", "xhigh"]
9
+ RESPONSES_LEVELS = ["low", "medium", "high"]
10
+ RESPONSES_GPT51_LEVELS = ["none", "low", "medium", "high"]
11
+ RESPONSES_GPT52_LEVELS = ["none", "low", "medium", "high", "xhigh"]
12
12
  RESPONSES_CODEX_MAX_LEVELS = ["medium", "high", "xhigh"]
13
13
 
14
14
  ANTHROPIC_LEVELS: list[tuple[str, int | None]] = [
@@ -206,6 +206,7 @@ class ThinkingCommand(CommandABC):
206
206
 
207
207
  # Apply the new thinking configuration
208
208
  config.thinking = new_thinking
209
+ agent.session.model_thinking = new_thinking
209
210
  new_status = _format_current_thinking(config)
210
211
 
211
212
  return CommandResult(
@@ -90,11 +90,13 @@ class InputActionExecutor:
90
90
  sub_agent_manager: SubAgentManager,
91
91
  model_profile_provider: ModelProfileProvider,
92
92
  emit_event: Callable[[events.Event], Awaitable[None]],
93
+ on_model_change: Callable[[str], None] | None = None,
93
94
  ) -> None:
94
95
  self._task_manager = task_manager
95
96
  self._sub_agent_manager = sub_agent_manager
96
97
  self._model_profile_provider = model_profile_provider
97
98
  self._emit_event = emit_event
99
+ self._on_model_change = on_model_change
98
100
 
99
101
  async def run(self, action: InputAction, operation: op.UserInputOperation, agent: Agent) -> None:
100
102
  """Dispatch and execute a single input action."""
@@ -208,6 +210,9 @@ class InputActionExecutor:
208
210
  llm_client = create_llm_client(llm_config)
209
211
  agent.set_model_profile(self._model_profile_provider.build_profile(llm_client))
210
212
 
213
+ agent.session.model_config_name = model_name
214
+ agent.session.model_thinking = llm_config.thinking
215
+
211
216
  developer_item = model.DeveloperMessageItem(
212
217
  content=f"switched to model: {model_name}",
213
218
  command_output=model.CommandOutput(command_name=commands.CommandName.MODEL),
@@ -217,11 +222,16 @@ class InputActionExecutor:
217
222
  await self._emit_event(events.DeveloperMessageEvent(session_id=agent.session.id, item=developer_item))
218
223
  await self._emit_event(events.WelcomeEvent(llm_config=llm_config, work_dir=str(agent.session.work_dir)))
219
224
 
225
+ if self._on_model_change is not None:
226
+ self._on_model_change(llm_client.model_name)
227
+
220
228
  async def _apply_clear(self, agent: Agent) -> None:
221
229
  """Start a new conversation for the agent and notify the UI."""
222
230
 
223
231
  new_session = Session(work_dir=agent.session.work_dir)
224
232
  new_session.model_name = agent.session.model_name
233
+ new_session.model_config_name = agent.session.model_config_name
234
+ new_session.model_thinking = agent.session.model_thinking
225
235
 
226
236
  agent.session = new_session
227
237
  agent.session.save()
@@ -249,6 +259,7 @@ class ExecutorContext:
249
259
  event_queue: asyncio.Queue[events.Event],
250
260
  llm_clients: LLMClients,
251
261
  model_profile_provider: ModelProfileProvider | None = None,
262
+ on_model_change: Callable[[str], None] | None = None,
252
263
  ):
253
264
  self.event_queue: asyncio.Queue[events.Event] = event_queue
254
265
  self.llm_clients: LLMClients = llm_clients
@@ -263,6 +274,7 @@ class ExecutorContext:
263
274
  sub_agent_manager=self.sub_agent_manager,
264
275
  model_profile_provider=resolved_profile_provider,
265
276
  emit_event=self.emit_event,
277
+ on_model_change=on_model_change,
266
278
  )
267
279
  self._agent: Agent | None = None
268
280
 
@@ -302,6 +314,13 @@ class ExecutorContext:
302
314
 
303
315
  session = Session.create() if session_id is None else Session.load(session_id)
304
316
 
317
+ if (
318
+ session.model_thinking is not None
319
+ and session.model_name
320
+ and session.model_name == self.llm_clients.main.model_name
321
+ ):
322
+ self.llm_clients.main.get_llm_config().thinking = session.model_thinking
323
+
305
324
  profile = self.model_profile_provider.build_profile(self.llm_clients.main)
306
325
  agent = Agent(session=session, profile=profile)
307
326
 
@@ -439,8 +458,9 @@ class Executor:
439
458
  event_queue: asyncio.Queue[events.Event],
440
459
  llm_clients: LLMClients,
441
460
  model_profile_provider: ModelProfileProvider | None = None,
461
+ on_model_change: Callable[[str], None] | None = None,
442
462
  ):
443
- self.context = ExecutorContext(event_queue, llm_clients, model_profile_provider)
463
+ self.context = ExecutorContext(event_queue, llm_clients, model_profile_provider, on_model_change)
444
464
  self.submission_queue: asyncio.Queue[op.Submission] = asyncio.Queue()
445
465
  # Track completion events for all submissions (not just those with ActiveTask)
446
466
  self._completion_events: dict[str, asyncio.Event] = {}