klaude-code 1.6.0__tar.gz → 1.7.0__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 (218) hide show
  1. {klaude_code-1.6.0 → klaude_code-1.7.0}/PKG-INFO +33 -5
  2. {klaude_code-1.6.0 → klaude_code-1.7.0}/README.md +31 -4
  3. {klaude_code-1.6.0 → klaude_code-1.7.0}/pyproject.toml +2 -1
  4. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/list_model.py +55 -4
  5. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/session_cmd.py +3 -2
  6. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/assets/builtin_config.yaml +37 -2
  7. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/builtin_config.py +1 -0
  8. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/config.py +14 -0
  9. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/thinking.py +14 -0
  10. klaude_code-1.7.0/src/klaude_code/llm/anthropic/client.py +233 -0
  11. klaude_code-1.7.0/src/klaude_code/llm/bedrock/__init__.py +3 -0
  12. klaude_code-1.7.0/src/klaude_code/llm/bedrock/client.py +60 -0
  13. klaude_code-1.7.0/src/klaude_code/llm/google/__init__.py +3 -0
  14. klaude_code-1.7.0/src/klaude_code/llm/google/client.py +309 -0
  15. klaude_code-1.7.0/src/klaude_code/llm/google/input.py +215 -0
  16. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/registry.py +10 -5
  17. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/llm_param.py +9 -0
  18. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/session.py +3 -1
  19. klaude_code-1.6.0/src/klaude_code/llm/anthropic/client.py +0 -220
  20. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/__init__.py +0 -0
  21. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/auth/__init__.py +0 -0
  22. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/auth/codex/__init__.py +0 -0
  23. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/auth/codex/exceptions.py +0 -0
  24. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
  25. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/auth/codex/oauth.py +0 -0
  26. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/auth/codex/token_manager.py +0 -0
  27. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/__init__.py +0 -0
  28. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/auth_cmd.py +0 -0
  29. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/config_cmd.py +0 -0
  30. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/debug.py +0 -0
  31. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/main.py +0 -0
  32. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/runtime.py +0 -0
  33. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/self_update.py +0 -0
  34. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/__init__.py +0 -0
  35. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/clear_cmd.py +0 -0
  36. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/command_abc.py +0 -0
  37. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/debug_cmd.py +0 -0
  38. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/export_cmd.py +0 -0
  39. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/export_online_cmd.py +0 -0
  40. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/fork_session_cmd.py +0 -0
  41. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/help_cmd.py +0 -0
  42. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/model_cmd.py +0 -0
  43. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/model_select.py +0 -0
  44. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/prompt-init.md +0 -0
  45. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/prompt-jj-describe.md +0 -0
  46. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/prompt_command.py +0 -0
  47. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/refresh_cmd.py +0 -0
  48. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/registry.py +0 -0
  49. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/release_notes_cmd.py +0 -0
  50. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/resume_cmd.py +0 -0
  51. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/status_cmd.py +0 -0
  52. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/terminal_setup_cmd.py +0 -0
  53. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/thinking_cmd.py +0 -0
  54. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/__init__.py +0 -0
  55. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/assets/__init__.py +0 -0
  56. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/select_model.py +0 -0
  57. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/const.py +0 -0
  58. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/__init__.py +0 -0
  59. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/agent.py +0 -0
  60. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/executor.py +0 -0
  61. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/manager/__init__.py +0 -0
  62. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/manager/llm_clients.py +0 -0
  63. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/manager/llm_clients_builder.py +0 -0
  64. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/manager/sub_agent_manager.py +0 -0
  65. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompt.py +0 -0
  66. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-claude-code.md +0 -0
  67. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +0 -0
  68. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +0 -0
  69. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-codex.md +0 -0
  70. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-gemini.md +0 -0
  71. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-minimal.md +0 -0
  72. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-sub-agent-explore.md +0 -0
  73. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-sub-agent-oracle.md +0 -0
  74. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-sub-agent-web.md +0 -0
  75. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-sub-agent.md +0 -0
  76. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/reminders.py +0 -0
  77. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/task.py +0 -0
  78. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/__init__.py +0 -0
  79. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/__init__.py +0 -0
  80. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/_utils.py +0 -0
  81. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/apply_patch.py +0 -0
  82. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
  83. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/apply_patch_tool.py +0 -0
  84. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/diff_builder.py +0 -0
  85. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
  86. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/edit_tool.py +0 -0
  87. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/move_tool.md +0 -0
  88. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/move_tool.py +0 -0
  89. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/read_tool.md +0 -0
  90. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/read_tool.py +0 -0
  91. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/write_tool.md +0 -0
  92. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/write_tool.py +0 -0
  93. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/report_back_tool.py +0 -0
  94. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/shell/__init__.py +0 -0
  95. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
  96. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/shell/bash_tool.py +0 -0
  97. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/shell/command_safety.py +0 -0
  98. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/skill/__init__.py +0 -0
  99. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/skill/skill_tool.md +0 -0
  100. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/skill/skill_tool.py +0 -0
  101. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/sub_agent_tool.py +0 -0
  102. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/todo/__init__.py +0 -0
  103. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
  104. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/todo/todo_write_tool.py +0 -0
  105. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
  106. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
  107. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
  108. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/tool_abc.py +0 -0
  109. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/tool_context.py +0 -0
  110. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/tool_registry.py +0 -0
  111. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/tool_runner.py +0 -0
  112. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/truncation.py +0 -0
  113. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/__init__.py +0 -0
  114. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/mermaid_tool.md +0 -0
  115. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/mermaid_tool.py +0 -0
  116. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/web_fetch_tool.md +0 -0
  117. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/web_fetch_tool.py +0 -0
  118. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/web_search_tool.md +0 -0
  119. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/web_search_tool.py +0 -0
  120. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/turn.py +0 -0
  121. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/__init__.py +0 -0
  122. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/anthropic/__init__.py +0 -0
  123. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/anthropic/input.py +0 -0
  124. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/client.py +0 -0
  125. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/codex/__init__.py +0 -0
  126. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/codex/client.py +0 -0
  127. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/input_common.py +0 -0
  128. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
  129. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openai_compatible/client.py +0 -0
  130. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openai_compatible/input.py +0 -0
  131. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openai_compatible/stream.py +0 -0
  132. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -0
  133. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openrouter/__init__.py +0 -0
  134. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openrouter/client.py +0 -0
  135. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openrouter/input.py +0 -0
  136. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openrouter/reasoning.py +0 -0
  137. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/responses/__init__.py +0 -0
  138. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/responses/client.py +0 -0
  139. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/responses/input.py +0 -0
  140. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/usage.py +0 -0
  141. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/__init__.py +0 -0
  142. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/commands.py +0 -0
  143. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/events.py +0 -0
  144. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/model.py +0 -0
  145. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/op.py +0 -0
  146. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/op_handler.py +0 -0
  147. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/sub_agent/__init__.py +0 -0
  148. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/sub_agent/explore.py +0 -0
  149. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/sub_agent/oracle.py +0 -0
  150. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/sub_agent/task.py +0 -0
  151. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/sub_agent/web.py +0 -0
  152. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/tools.py +0 -0
  153. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/__init__.py +0 -0
  154. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/codec.py +0 -0
  155. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/export.py +0 -0
  156. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/selector.py +0 -0
  157. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/store.py +0 -0
  158. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/templates/export_session.html +0 -0
  159. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/templates/mermaid_viewer.html +0 -0
  160. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/__init__.py +0 -0
  161. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/assets/deslop/SKILL.md +0 -0
  162. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/assets/dev-docs/SKILL.md +0 -0
  163. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/assets/handoff/SKILL.md +0 -0
  164. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/assets/jj-workspace/SKILL.md +0 -0
  165. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/assets/skill-creator/SKILL.md +0 -0
  166. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/loader.py +0 -0
  167. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/manager.py +0 -0
  168. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/system_skills.py +0 -0
  169. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/trace/__init__.py +0 -0
  170. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/trace/log.py +0 -0
  171. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/__init__.py +0 -0
  172. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/core/__init__.py +0 -0
  173. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/core/display.py +0 -0
  174. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/core/input.py +0 -0
  175. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/core/stage_manager.py +0 -0
  176. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/__init__.py +0 -0
  177. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/debug/__init__.py +0 -0
  178. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/debug/display.py +0 -0
  179. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/exec/__init__.py +0 -0
  180. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/exec/display.py +0 -0
  181. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/__init__.py +0 -0
  182. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/clipboard.py +0 -0
  183. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/completers.py +0 -0
  184. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/display.py +0 -0
  185. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/event_handler.py +0 -0
  186. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/input_prompt_toolkit.py +0 -0
  187. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/key_bindings.py +0 -0
  188. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/renderer.py +0 -0
  189. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/__init__.py +0 -0
  190. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/assistant.py +0 -0
  191. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/bash_syntax.py +0 -0
  192. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/common.py +0 -0
  193. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/developer.py +0 -0
  194. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/diffs.py +0 -0
  195. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/errors.py +0 -0
  196. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/mermaid_viewer.py +0 -0
  197. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/metadata.py +0 -0
  198. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/sub_agent.py +0 -0
  199. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/thinking.py +0 -0
  200. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/tools.py +0 -0
  201. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/user_input.py +0 -0
  202. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/__init__.py +0 -0
  203. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/cjk_wrap.py +0 -0
  204. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/code_panel.py +0 -0
  205. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/live.py +0 -0
  206. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/markdown.py +0 -0
  207. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/quote.py +0 -0
  208. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/searchable_text.py +0 -0
  209. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/status.py +0 -0
  210. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/theme.py +0 -0
  211. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/terminal/__init__.py +0 -0
  212. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/terminal/color.py +0 -0
  213. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/terminal/control.py +0 -0
  214. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/terminal/notifier.py +0 -0
  215. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/terminal/progress_bar.py +0 -0
  216. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/terminal/selector.py +0 -0
  217. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/utils/__init__.py +0 -0
  218. {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/utils/common.py +0 -0
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 1.6.0
3
+ Version: 1.7.0
4
4
  Summary: Minimal code agent CLI
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: chardet>=5.2.0
7
7
  Requires-Dist: ddgs>=9.9.3
8
8
  Requires-Dist: diff-match-patch>=20241021
9
+ Requires-Dist: google-genai>=1.56.0
9
10
  Requires-Dist: markdown-it-py>=4.0.0
10
11
  Requires-Dist: openai>=1.102.0
11
12
  Requires-Dist: pillow>=12.0.0
@@ -34,6 +35,10 @@ Minimal code agent CLI.
34
35
  - **Output truncation**: Large outputs saved to file system with snapshot links
35
36
  - **Skills**: Built-in + user + project Agent Skills (with implicit invocation by Skill tool or explicit invocation by typing `$`)
36
37
  - **Sessions**: Resumable with `--continue`
38
+ - **Cost tracking**: Automatic API cost calculation and display (USD/CNY)
39
+ - **Version update check**: Background PyPI version check with upgrade prompts
40
+ - **Terminal title**: Shows current directory and model name
41
+ - **Mermaid diagrams**: Interactive local HTML viewer with zoom, pan, and SVG export
37
42
  - **Extras**: Slash commands, sub-agents, image paste, terminal notifications, auto-theming
38
43
 
39
44
  ## Installation
@@ -77,6 +82,7 @@ klaude [--model <name>] [--select-model]
77
82
  - `--select-model`/`-s`: Open the interactive model selector at startup (shows all models unless `--model` is also provided).
78
83
  - `--continue`/`-c`: Resume the most recent session.
79
84
  - `--resume`/`-r`: Select a session to resume for this project.
85
+ - `--resume-by-id <id>`: Resume a session by its ID directly.
80
86
  - `--vanilla`: Minimal mode with only basic tools (Bash, Read, Edit) and no system prompts.
81
87
 
82
88
  **Model selection behavior:**
@@ -251,12 +257,18 @@ klaude session clean-all
251
257
 
252
258
  Inside the interactive session (`klaude`), use these commands to streamline your workflow:
253
259
 
254
- - `/dev-doc [feature]` - Generate a comprehensive execution plan for a feature.
255
- - `/export` - Export last assistant message to a temp Markdown file.
256
- - `/init` - Bootstrap a new project structure or module.
257
260
  - `/model` - Switch the active LLM during the session.
261
+ - `/thinking` - Configure model thinking/reasoning level.
258
262
  - `/clear` - Clear the current conversation context.
259
- - `/diff` - Show local git diff changes.
263
+ - `/status` - Show session usage statistics (cost, tokens, model breakdown).
264
+ - `/resume` - Select and resume a previous session.
265
+ - `/fork-session` - Fork current session to a new session ID (supports interactive fork point selection).
266
+ - `/export` - Export last assistant message to a temp Markdown file.
267
+ - `/export-online` - Export and deploy session to surge.sh as a static webpage.
268
+ - `/debug [filters]` - Toggle debug mode and configure debug filters.
269
+ - `/init` - Bootstrap a new project structure or module.
270
+ - `/dev-doc [feature]` - Generate a comprehensive execution plan for a feature.
271
+ - `/terminal-setup` - Configure terminal for Shift+Enter support.
260
272
  - `/help` - List all available commands.
261
273
 
262
274
 
@@ -267,6 +279,8 @@ Inside the interactive session (`klaude`), use these commands to streamline your
267
279
  | `Enter` | Submit input |
268
280
  | `Shift+Enter` | Insert newline (requires `/terminal-setup`) |
269
281
  | `Ctrl+J` | Insert newline |
282
+ | `Ctrl+L` | Open model picker overlay |
283
+ | `Ctrl+T` | Open thinking level picker overlay |
270
284
  | `Ctrl+V` | Paste image from clipboard |
271
285
  | `Left/Right` | Move cursor (wraps across lines) |
272
286
  | `Backspace` | Delete character or selected text |
@@ -290,4 +304,18 @@ echo "generate quicksort in python" | klaude exec --model gpt-5.1
290
304
 
291
305
  # Partial/ambiguous name opens the interactive selector (filtered)
292
306
  echo "generate quicksort in python" | klaude exec --model gpt
307
+
308
+ # Stream all events as JSON lines (for programmatic processing)
309
+ klaude exec "what is 2+2?" --stream-json
293
310
  ```
311
+
312
+ ### Sub-Agents
313
+
314
+ The main agent can spawn specialized sub-agents for specific tasks:
315
+
316
+ | Sub-Agent | Purpose |
317
+ |-----------|---------|
318
+ | **Explore** | Fast codebase exploration - find files, search code, answer questions about the codebase |
319
+ | **Task** | Handle complex multi-step tasks autonomously |
320
+ | **WebAgent** | Search the web, fetch pages, and analyze content |
321
+ | **Oracle** | Advanced reasoning advisor for code reviews, architecture planning, and bug analysis |
@@ -14,6 +14,10 @@ Minimal code agent CLI.
14
14
  - **Output truncation**: Large outputs saved to file system with snapshot links
15
15
  - **Skills**: Built-in + user + project Agent Skills (with implicit invocation by Skill tool or explicit invocation by typing `$`)
16
16
  - **Sessions**: Resumable with `--continue`
17
+ - **Cost tracking**: Automatic API cost calculation and display (USD/CNY)
18
+ - **Version update check**: Background PyPI version check with upgrade prompts
19
+ - **Terminal title**: Shows current directory and model name
20
+ - **Mermaid diagrams**: Interactive local HTML viewer with zoom, pan, and SVG export
17
21
  - **Extras**: Slash commands, sub-agents, image paste, terminal notifications, auto-theming
18
22
 
19
23
  ## Installation
@@ -57,6 +61,7 @@ klaude [--model <name>] [--select-model]
57
61
  - `--select-model`/`-s`: Open the interactive model selector at startup (shows all models unless `--model` is also provided).
58
62
  - `--continue`/`-c`: Resume the most recent session.
59
63
  - `--resume`/`-r`: Select a session to resume for this project.
64
+ - `--resume-by-id <id>`: Resume a session by its ID directly.
60
65
  - `--vanilla`: Minimal mode with only basic tools (Bash, Read, Edit) and no system prompts.
61
66
 
62
67
  **Model selection behavior:**
@@ -231,12 +236,18 @@ klaude session clean-all
231
236
 
232
237
  Inside the interactive session (`klaude`), use these commands to streamline your workflow:
233
238
 
234
- - `/dev-doc [feature]` - Generate a comprehensive execution plan for a feature.
235
- - `/export` - Export last assistant message to a temp Markdown file.
236
- - `/init` - Bootstrap a new project structure or module.
237
239
  - `/model` - Switch the active LLM during the session.
240
+ - `/thinking` - Configure model thinking/reasoning level.
238
241
  - `/clear` - Clear the current conversation context.
239
- - `/diff` - Show local git diff changes.
242
+ - `/status` - Show session usage statistics (cost, tokens, model breakdown).
243
+ - `/resume` - Select and resume a previous session.
244
+ - `/fork-session` - Fork current session to a new session ID (supports interactive fork point selection).
245
+ - `/export` - Export last assistant message to a temp Markdown file.
246
+ - `/export-online` - Export and deploy session to surge.sh as a static webpage.
247
+ - `/debug [filters]` - Toggle debug mode and configure debug filters.
248
+ - `/init` - Bootstrap a new project structure or module.
249
+ - `/dev-doc [feature]` - Generate a comprehensive execution plan for a feature.
250
+ - `/terminal-setup` - Configure terminal for Shift+Enter support.
240
251
  - `/help` - List all available commands.
241
252
 
242
253
 
@@ -247,6 +258,8 @@ Inside the interactive session (`klaude`), use these commands to streamline your
247
258
  | `Enter` | Submit input |
248
259
  | `Shift+Enter` | Insert newline (requires `/terminal-setup`) |
249
260
  | `Ctrl+J` | Insert newline |
261
+ | `Ctrl+L` | Open model picker overlay |
262
+ | `Ctrl+T` | Open thinking level picker overlay |
250
263
  | `Ctrl+V` | Paste image from clipboard |
251
264
  | `Left/Right` | Move cursor (wraps across lines) |
252
265
  | `Backspace` | Delete character or selected text |
@@ -270,4 +283,18 @@ echo "generate quicksort in python" | klaude exec --model gpt-5.1
270
283
 
271
284
  # Partial/ambiguous name opens the interactive selector (filtered)
272
285
  echo "generate quicksort in python" | klaude exec --model gpt
286
+
287
+ # Stream all events as JSON lines (for programmatic processing)
288
+ klaude exec "what is 2+2?" --stream-json
273
289
  ```
290
+
291
+ ### Sub-Agents
292
+
293
+ The main agent can spawn specialized sub-agents for specific tasks:
294
+
295
+ | Sub-Agent | Purpose |
296
+ |-----------|---------|
297
+ | **Explore** | Fast codebase exploration - find files, search code, answer questions about the codebase |
298
+ | **Task** | Handle complex multi-step tasks autonomously |
299
+ | **WebAgent** | Search the web, fetch pages, and analyze content |
300
+ | **Oracle** | Advanced reasoning advisor for code reviews, architecture planning, and bug analysis |
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "klaude-code"
7
- version = "1.6.0"
7
+ version = "1.7.0"
8
8
  description = "Minimal code agent CLI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -13,6 +13,7 @@ dependencies = [
13
13
  "chardet>=5.2.0",
14
14
  "ddgs>=9.9.3",
15
15
  "diff-match-patch>=20241021",
16
+ "google-genai>=1.56.0",
16
17
  "markdown-it-py>=4.0.0",
17
18
  "openai>=1.102.0",
18
19
  "pillow>=12.0.0",
@@ -6,7 +6,7 @@ from rich.table import Table
6
6
  from rich.text import Text
7
7
 
8
8
  from klaude_code.config import Config
9
- from klaude_code.config.config import ModelConfig, ProviderConfig
9
+ from klaude_code.config.config import ModelConfig, ProviderConfig, parse_env_var_syntax
10
10
  from klaude_code.protocol.llm_param import LLMClientProtocol
11
11
  from klaude_code.protocol.sub_agent import iter_sub_agent_profiles
12
12
  from klaude_code.ui.rich.theme import ThemeKey, get_theme
@@ -94,6 +94,29 @@ def format_api_key_display(provider: ProviderConfig) -> Text:
94
94
  return Text("N/A")
95
95
 
96
96
 
97
+ def format_env_var_display(value: str | None) -> Text:
98
+ """Format environment variable display with warning if not set."""
99
+ env_var, resolved = parse_env_var_syntax(value)
100
+
101
+ if env_var:
102
+ # Using ${ENV_VAR} syntax
103
+ if resolved:
104
+ return Text.assemble(
105
+ (f"${{{env_var}}} = ", "dim"),
106
+ (mask_api_key(resolved), ""),
107
+ )
108
+ else:
109
+ return Text.assemble(
110
+ (f"${{{env_var}}} ", ""),
111
+ ("(not set)", ThemeKey.CONFIG_STATUS_ERROR),
112
+ )
113
+ elif value:
114
+ # Plain value
115
+ return Text(mask_api_key(value))
116
+ else:
117
+ return Text("N/A")
118
+
119
+
97
120
  def _get_model_params_display(model: ModelConfig) -> list[Text]:
98
121
  """Get display elements for model parameters."""
99
122
  params: list[Text] = []
@@ -162,15 +185,43 @@ def display_models_and_providers(config: Config):
162
185
  format_api_key_display(provider),
163
186
  )
164
187
 
188
+ # AWS Bedrock parameters
189
+ if provider.protocol == LLMClientProtocol.BEDROCK:
190
+ if provider.aws_access_key:
191
+ provider_info.add_row(
192
+ Text("AWS Key:", style=ThemeKey.CONFIG_PARAM_LABEL),
193
+ format_env_var_display(provider.aws_access_key),
194
+ )
195
+ if provider.aws_secret_key:
196
+ provider_info.add_row(
197
+ Text("AWS Secret:", style=ThemeKey.CONFIG_PARAM_LABEL),
198
+ format_env_var_display(provider.aws_secret_key),
199
+ )
200
+ if provider.aws_region:
201
+ provider_info.add_row(
202
+ Text("AWS Region:", style=ThemeKey.CONFIG_PARAM_LABEL),
203
+ format_env_var_display(provider.aws_region),
204
+ )
205
+ if provider.aws_session_token:
206
+ provider_info.add_row(
207
+ Text("AWS Token:", style=ThemeKey.CONFIG_PARAM_LABEL),
208
+ format_env_var_display(provider.aws_session_token),
209
+ )
210
+ if provider.aws_profile:
211
+ provider_info.add_row(
212
+ Text("AWS Profile:", style=ThemeKey.CONFIG_PARAM_LABEL),
213
+ format_env_var_display(provider.aws_profile),
214
+ )
215
+
165
216
  # Check if provider has valid API key
166
217
  provider_available = not provider.is_api_key_missing()
167
218
 
168
219
  # Models table for this provider
169
220
  models_table = Table.grid(padding=(0, 1), expand=True)
170
221
  models_table.add_column(width=2, no_wrap=True) # Status
171
- models_table.add_column(overflow="fold", ratio=1) # Name
172
- models_table.add_column(overflow="fold", ratio=2) # Model
173
- models_table.add_column(overflow="fold", ratio=3) # Params
222
+ models_table.add_column(overflow="fold", ratio=2) # Name
223
+ models_table.add_column(overflow="fold", ratio=3) # Model
224
+ models_table.add_column(overflow="fold", ratio=4) # Params
174
225
 
175
226
  # Add header
176
227
  models_table.add_row(
@@ -22,8 +22,9 @@ def _session_confirm(sessions: list[Session.SessionMetaBrief], message: str) ->
22
22
  log(f"Sessions to delete ({len(sessions)}):")
23
23
  for s in sessions:
24
24
  msg_count_display = "N/A" if s.messages_count == -1 else str(s.messages_count)
25
- first_msg = (s.first_user_message or "").strip().replace("\n", " ")[:50]
26
- if len(s.first_user_message or "") > 50:
25
+ first_msg_text = s.user_messages[0] if s.user_messages else ""
26
+ first_msg = first_msg_text.strip().replace("\n", " ")[:50]
27
+ if len(first_msg_text) > 50:
27
28
  first_msg += "..."
28
29
  log(f" {_fmt(s.updated_at)} {msg_count_display:>3} msgs {first_msg}")
29
30
 
@@ -7,7 +7,7 @@ provider_list:
7
7
  protocol: anthropic
8
8
  api_key: ${ANTHROPIC_API_KEY}
9
9
  model_list:
10
- - model_name: sonnet
10
+ - model_name: sonnet@ant
11
11
  model_params:
12
12
  model: claude-sonnet-4-5-20250929
13
13
  context_limit: 200000
@@ -18,7 +18,7 @@ provider_list:
18
18
  output: 15.0
19
19
  cache_read: 0.3
20
20
  cache_write: 3.75
21
- - model_name: opus
21
+ - model_name: opus@ant
22
22
  model_params:
23
23
  model: claude-opus-4-5-20251101
24
24
  context_limit: 200000
@@ -194,6 +194,41 @@ provider_list:
194
194
  output: 1.74
195
195
  cache_read: 0.04
196
196
 
197
+ - provider_name: google
198
+ protocol: google
199
+ api_key: ${GOOGLE_API_KEY}
200
+ model_list:
201
+ - model_name: gemini-pro@google
202
+ model_params:
203
+ model: gemini-3-pro-preview
204
+ context_limit: 1048576
205
+ cost:
206
+ input: 2.0
207
+ output: 12.0
208
+ cache_read: 0.2
209
+ - model_name: gemini-flash@google
210
+ model_params:
211
+ model: gemini-3-flash-preview
212
+ context_limit: 1048576
213
+ cost:
214
+ input: 0.5
215
+ output: 3.0
216
+ cache_read: 0.05
217
+ - provider_name: bedrock
218
+ protocol: bedrock
219
+ aws_access_key: ${AWS_ACCESS_KEY_ID}
220
+ aws_secret_key: ${AWS_SECRET_ACCESS_KEY}
221
+ aws_region: ${AWS_REGION}
222
+ model_list:
223
+ - model_name: sonnet@bedrock
224
+ model_params:
225
+ model: us.anthropic.claude-sonnet-4-5-20250929-v1:0
226
+ context_limit: 200000
227
+ cost:
228
+ input: 3.0
229
+ output: 15.0
230
+ cache_read: 0.3
231
+ cache_write: 3.75
197
232
  - provider_name: deepseek
198
233
  protocol: anthropic
199
234
  api_key: ${DEEPSEEK_API_KEY}
@@ -17,6 +17,7 @@ if TYPE_CHECKING:
17
17
  # All supported API key environment variables
18
18
  SUPPORTED_API_KEY_ENVS = [
19
19
  "ANTHROPIC_API_KEY",
20
+ "GOOGLE_API_KEY",
20
21
  "OPENAI_API_KEY",
21
22
  "OPENROUTER_API_KEY",
22
23
  "DEEPSEEK_API_KEY",
@@ -77,6 +77,7 @@ class ProviderConfig(llm_param.LLMConfigProviderParameter):
77
77
  """Check if the API key is missing (either not set or env var not found).
78
78
 
79
79
  For codex protocol, checks OAuth login status instead of API key.
80
+ For bedrock protocol, checks AWS credentials instead of API key.
80
81
  """
81
82
  from klaude_code.protocol.llm_param import LLMClientProtocol
82
83
 
@@ -89,6 +90,19 @@ class ProviderConfig(llm_param.LLMConfigProviderParameter):
89
90
  # Consider available if logged in and token not expired
90
91
  return state is None or state.is_expired()
91
92
 
93
+ if self.protocol == LLMClientProtocol.BEDROCK:
94
+ # Bedrock uses AWS credentials, not API key. Region is always required.
95
+ _, resolved_profile = parse_env_var_syntax(self.aws_profile)
96
+ _, resolved_region = parse_env_var_syntax(self.aws_region)
97
+
98
+ # When using profile, we still need region to initialize the client.
99
+ if resolved_profile:
100
+ return resolved_region is None
101
+
102
+ _, resolved_access_key = parse_env_var_syntax(self.aws_access_key)
103
+ _, resolved_secret_key = parse_env_var_syntax(self.aws_secret_key)
104
+ return resolved_region is None or resolved_access_key is None or resolved_secret_key is None
105
+
92
106
  return self.get_resolved_api_key() is None
93
107
 
94
108
 
@@ -121,6 +121,13 @@ def format_current_thinking(config: llm_param.LLMConfigParameter) -> str:
121
121
  return f"enabled (budget_tokens={thinking.budget_tokens})"
122
122
  return "not set"
123
123
 
124
+ if protocol == llm_param.LLMClientProtocol.GOOGLE:
125
+ if thinking.type == "disabled":
126
+ return "off"
127
+ if thinking.type == "enabled":
128
+ return f"enabled (budget_tokens={thinking.budget_tokens})"
129
+ return "not set"
130
+
124
131
  return "unknown protocol"
125
132
 
126
133
 
@@ -230,6 +237,13 @@ def get_thinking_picker_data(config: llm_param.LLMConfigParameter) -> ThinkingPi
230
237
  current_value=_get_current_budget_value(thinking),
231
238
  )
232
239
 
240
+ if protocol == llm_param.LLMClientProtocol.GOOGLE:
241
+ return ThinkingPickerData(
242
+ options=_build_budget_options(),
243
+ message="Select thinking level:",
244
+ current_value=_get_current_budget_value(thinking),
245
+ )
246
+
233
247
  return None
234
248
 
235
249
 
@@ -0,0 +1,233 @@
1
+ import json
2
+ import os
3
+ from collections.abc import AsyncGenerator
4
+ from typing import Any, override
5
+
6
+ import anthropic
7
+ import httpx
8
+ from anthropic import APIError
9
+ from anthropic.types.beta.beta_input_json_delta import BetaInputJSONDelta
10
+ from anthropic.types.beta.beta_raw_content_block_delta_event import BetaRawContentBlockDeltaEvent
11
+ from anthropic.types.beta.beta_raw_content_block_start_event import BetaRawContentBlockStartEvent
12
+ from anthropic.types.beta.beta_raw_content_block_stop_event import BetaRawContentBlockStopEvent
13
+ from anthropic.types.beta.beta_raw_message_delta_event import BetaRawMessageDeltaEvent
14
+ from anthropic.types.beta.beta_raw_message_start_event import BetaRawMessageStartEvent
15
+ from anthropic.types.beta.beta_signature_delta import BetaSignatureDelta
16
+ from anthropic.types.beta.beta_text_delta import BetaTextDelta
17
+ from anthropic.types.beta.beta_thinking_delta import BetaThinkingDelta
18
+ from anthropic.types.beta.beta_tool_use_block import BetaToolUseBlock
19
+ from anthropic.types.beta.message_create_params import MessageCreateParamsStreaming
20
+
21
+ from klaude_code import const
22
+ from klaude_code.llm.anthropic.input import convert_history_to_input, convert_system_to_input, convert_tool_schema
23
+ from klaude_code.llm.client import LLMClientABC
24
+ from klaude_code.llm.input_common import apply_config_defaults
25
+ from klaude_code.llm.registry import register
26
+ from klaude_code.llm.usage import MetadataTracker
27
+ from klaude_code.protocol import llm_param, model
28
+ from klaude_code.trace import DebugType, log_debug
29
+
30
+
31
+ def build_payload(param: llm_param.LLMCallParameter) -> MessageCreateParamsStreaming:
32
+ """Build Anthropic API request parameters."""
33
+ messages = convert_history_to_input(param.input, param.model)
34
+ tools = convert_tool_schema(param.tools)
35
+ system = convert_system_to_input(param.system)
36
+
37
+ payload: MessageCreateParamsStreaming = {
38
+ "model": str(param.model),
39
+ "tool_choice": {
40
+ "type": "auto",
41
+ "disable_parallel_tool_use": False,
42
+ },
43
+ "stream": True,
44
+ "max_tokens": param.max_tokens or const.DEFAULT_MAX_TOKENS,
45
+ "temperature": param.temperature or const.DEFAULT_TEMPERATURE,
46
+ "messages": messages,
47
+ "system": system,
48
+ "tools": tools,
49
+ "betas": ["interleaved-thinking-2025-05-14", "context-1m-2025-08-07"],
50
+ }
51
+
52
+ if param.thinking and param.thinking.type == "enabled":
53
+ payload["thinking"] = anthropic.types.ThinkingConfigEnabledParam(
54
+ type="enabled",
55
+ budget_tokens=param.thinking.budget_tokens or const.DEFAULT_ANTHROPIC_THINKING_BUDGET_TOKENS,
56
+ )
57
+
58
+ return payload
59
+
60
+
61
+ async def parse_anthropic_stream(
62
+ stream: Any,
63
+ param: llm_param.LLMCallParameter,
64
+ metadata_tracker: MetadataTracker,
65
+ ) -> AsyncGenerator[model.ConversationItem]:
66
+ """Parse Anthropic beta messages stream and yield conversation items.
67
+
68
+ This function is shared between AnthropicClient and BedrockClient.
69
+ """
70
+ accumulated_thinking: list[str] = []
71
+ accumulated_content: list[str] = []
72
+ response_id: str | None = None
73
+
74
+ current_tool_name: str | None = None
75
+ current_tool_call_id: str | None = None
76
+ current_tool_inputs: list[str] | None = None
77
+
78
+ input_token = 0
79
+ cached_token = 0
80
+
81
+ async for event in await stream:
82
+ log_debug(
83
+ f"[{event.type}]",
84
+ event.model_dump_json(exclude_none=True),
85
+ style="blue",
86
+ debug_type=DebugType.LLM_STREAM,
87
+ )
88
+ match event:
89
+ case BetaRawMessageStartEvent() as event:
90
+ response_id = event.message.id
91
+ cached_token = event.message.usage.cache_read_input_tokens or 0
92
+ input_token = event.message.usage.input_tokens
93
+ yield model.StartItem(response_id=response_id)
94
+ case BetaRawContentBlockDeltaEvent() as event:
95
+ match event.delta:
96
+ case BetaThinkingDelta() as delta:
97
+ if delta.thinking:
98
+ metadata_tracker.record_token()
99
+ accumulated_thinking.append(delta.thinking)
100
+ yield model.ReasoningTextDelta(
101
+ content=delta.thinking,
102
+ response_id=response_id,
103
+ )
104
+ case BetaSignatureDelta() as delta:
105
+ yield model.ReasoningEncryptedItem(
106
+ encrypted_content=delta.signature,
107
+ response_id=response_id,
108
+ model=str(param.model),
109
+ )
110
+ case BetaTextDelta() as delta:
111
+ if delta.text:
112
+ metadata_tracker.record_token()
113
+ accumulated_content.append(delta.text)
114
+ yield model.AssistantMessageDelta(
115
+ content=delta.text,
116
+ response_id=response_id,
117
+ )
118
+ case BetaInputJSONDelta() as delta:
119
+ if current_tool_inputs is not None:
120
+ if delta.partial_json:
121
+ metadata_tracker.record_token()
122
+ current_tool_inputs.append(delta.partial_json)
123
+ case _:
124
+ pass
125
+ case BetaRawContentBlockStartEvent() as event:
126
+ match event.content_block:
127
+ case BetaToolUseBlock() as block:
128
+ metadata_tracker.record_token()
129
+ yield model.ToolCallStartItem(
130
+ response_id=response_id,
131
+ call_id=block.id,
132
+ name=block.name,
133
+ )
134
+ current_tool_name = block.name
135
+ current_tool_call_id = block.id
136
+ current_tool_inputs = []
137
+ case _:
138
+ pass
139
+ case BetaRawContentBlockStopEvent():
140
+ if len(accumulated_thinking) > 0:
141
+ metadata_tracker.record_token()
142
+ full_thinking = "".join(accumulated_thinking)
143
+ yield model.ReasoningTextItem(
144
+ content=full_thinking,
145
+ response_id=response_id,
146
+ model=str(param.model),
147
+ )
148
+ accumulated_thinking.clear()
149
+ if len(accumulated_content) > 0:
150
+ metadata_tracker.record_token()
151
+ yield model.AssistantMessageItem(
152
+ content="".join(accumulated_content),
153
+ response_id=response_id,
154
+ )
155
+ accumulated_content.clear()
156
+ if current_tool_name and current_tool_call_id:
157
+ metadata_tracker.record_token()
158
+ yield model.ToolCallItem(
159
+ name=current_tool_name,
160
+ call_id=current_tool_call_id,
161
+ arguments="".join(current_tool_inputs) if current_tool_inputs else "",
162
+ response_id=response_id,
163
+ )
164
+ current_tool_name = None
165
+ current_tool_call_id = None
166
+ current_tool_inputs = None
167
+ case BetaRawMessageDeltaEvent() as event:
168
+ metadata_tracker.set_usage(
169
+ model.Usage(
170
+ input_tokens=input_token + cached_token,
171
+ output_tokens=event.usage.output_tokens,
172
+ cached_tokens=cached_token,
173
+ context_size=input_token + cached_token + event.usage.output_tokens,
174
+ context_limit=param.context_limit,
175
+ max_tokens=param.max_tokens,
176
+ )
177
+ )
178
+ metadata_tracker.set_model_name(str(param.model))
179
+ metadata_tracker.set_response_id(response_id)
180
+ yield metadata_tracker.finalize()
181
+ case _:
182
+ pass
183
+
184
+
185
+ @register(llm_param.LLMClientProtocol.ANTHROPIC)
186
+ class AnthropicClient(LLMClientABC):
187
+ def __init__(self, config: llm_param.LLMConfigParameter):
188
+ super().__init__(config)
189
+ # Remove ANTHROPIC_AUTH_TOKEN env var to prevent anthropic SDK from adding
190
+ # Authorization: Bearer header that may conflict with third-party APIs
191
+ # (e.g., deepseek, moonshot) that use Authorization header for authentication.
192
+ # The API key will be sent via X-Api-Key header instead.
193
+ saved_auth_token = os.environ.pop("ANTHROPIC_AUTH_TOKEN", None)
194
+ try:
195
+ client = anthropic.AsyncAnthropic(
196
+ api_key=config.api_key,
197
+ base_url=config.base_url,
198
+ timeout=httpx.Timeout(300.0, connect=15.0, read=285.0),
199
+ )
200
+ finally:
201
+ if saved_auth_token is not None:
202
+ os.environ["ANTHROPIC_AUTH_TOKEN"] = saved_auth_token
203
+ self.client: anthropic.AsyncAnthropic = client
204
+
205
+ @classmethod
206
+ @override
207
+ def create(cls, config: llm_param.LLMConfigParameter) -> "LLMClientABC":
208
+ return cls(config)
209
+
210
+ @override
211
+ async def call(self, param: llm_param.LLMCallParameter) -> AsyncGenerator[model.ConversationItem]:
212
+ param = apply_config_defaults(param, self.get_llm_config())
213
+
214
+ metadata_tracker = MetadataTracker(cost_config=self.get_llm_config().cost)
215
+
216
+ payload = build_payload(param)
217
+
218
+ log_debug(
219
+ json.dumps(payload, ensure_ascii=False, default=str),
220
+ style="yellow",
221
+ debug_type=DebugType.LLM_PAYLOAD,
222
+ )
223
+
224
+ stream = self.client.beta.messages.create(
225
+ **payload,
226
+ extra_headers={"extra": json.dumps({"session_id": param.session_id}, sort_keys=True)},
227
+ )
228
+
229
+ try:
230
+ async for item in parse_anthropic_stream(stream, param, metadata_tracker):
231
+ yield item
232
+ except (APIError, httpx.HTTPError) as e:
233
+ yield model.StreamErrorItem(error=f"{e.__class__.__name__} {e!s}")
@@ -0,0 +1,3 @@
1
+ from klaude_code.llm.bedrock.client import BedrockClient
2
+
3
+ __all__ = ["BedrockClient"]