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.
- {klaude_code-1.6.0 → klaude_code-1.7.0}/PKG-INFO +33 -5
- {klaude_code-1.6.0 → klaude_code-1.7.0}/README.md +31 -4
- {klaude_code-1.6.0 → klaude_code-1.7.0}/pyproject.toml +2 -1
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/list_model.py +55 -4
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/session_cmd.py +3 -2
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/assets/builtin_config.yaml +37 -2
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/builtin_config.py +1 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/config.py +14 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/thinking.py +14 -0
- klaude_code-1.7.0/src/klaude_code/llm/anthropic/client.py +233 -0
- klaude_code-1.7.0/src/klaude_code/llm/bedrock/__init__.py +3 -0
- klaude_code-1.7.0/src/klaude_code/llm/bedrock/client.py +60 -0
- klaude_code-1.7.0/src/klaude_code/llm/google/__init__.py +3 -0
- klaude_code-1.7.0/src/klaude_code/llm/google/client.py +309 -0
- klaude_code-1.7.0/src/klaude_code/llm/google/input.py +215 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/registry.py +10 -5
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/llm_param.py +9 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/session.py +3 -1
- klaude_code-1.6.0/src/klaude_code/llm/anthropic/client.py +0 -220
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/auth/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/auth/codex/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/auth/codex/exceptions.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/auth/codex/oauth.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/auth/codex/token_manager.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/auth_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/config_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/debug.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/main.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/runtime.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/cli/self_update.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/clear_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/command_abc.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/debug_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/export_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/export_online_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/fork_session_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/help_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/model_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/model_select.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/prompt-init.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/prompt-jj-describe.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/prompt_command.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/refresh_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/registry.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/release_notes_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/resume_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/status_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/terminal_setup_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/command/thinking_cmd.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/assets/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/config/select_model.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/const.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/agent.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/executor.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/manager/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/manager/llm_clients.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/manager/llm_clients_builder.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/manager/sub_agent_manager.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompt.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-claude-code.md +0 -0
- {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
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-codex.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-gemini.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-minimal.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-sub-agent-explore.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-sub-agent-oracle.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-sub-agent-web.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/prompts/prompt-sub-agent.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/reminders.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/task.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/_utils.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/apply_patch.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/apply_patch_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/diff_builder.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/edit_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/move_tool.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/move_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/read_tool.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/read_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/write_tool.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/file/write_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/report_back_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/shell/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/shell/bash_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/shell/command_safety.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/skill/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/skill/skill_tool.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/skill/skill_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/sub_agent_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/todo/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/todo/todo_write_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/tool_abc.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/tool_context.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/tool_registry.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/tool_runner.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/truncation.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/mermaid_tool.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/mermaid_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/web_fetch_tool.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/web_fetch_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/web_search_tool.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/tool/web/web_search_tool.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/core/turn.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/anthropic/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/anthropic/input.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/client.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/codex/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/codex/client.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/input_common.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openai_compatible/client.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openai_compatible/input.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openai_compatible/stream.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openrouter/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openrouter/client.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openrouter/input.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/openrouter/reasoning.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/responses/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/responses/client.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/responses/input.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/llm/usage.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/commands.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/events.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/model.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/op.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/op_handler.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/sub_agent/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/sub_agent/explore.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/sub_agent/oracle.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/sub_agent/task.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/sub_agent/web.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/protocol/tools.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/codec.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/export.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/selector.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/store.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/templates/export_session.html +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/session/templates/mermaid_viewer.html +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/assets/deslop/SKILL.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/assets/dev-docs/SKILL.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/assets/handoff/SKILL.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/assets/jj-workspace/SKILL.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/assets/skill-creator/SKILL.md +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/loader.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/manager.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/skill/system_skills.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/trace/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/trace/log.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/core/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/core/display.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/core/input.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/core/stage_manager.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/debug/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/debug/display.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/exec/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/exec/display.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/clipboard.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/completers.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/display.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/event_handler.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/input_prompt_toolkit.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/key_bindings.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/modes/repl/renderer.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/assistant.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/bash_syntax.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/common.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/developer.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/diffs.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/errors.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/mermaid_viewer.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/metadata.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/sub_agent.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/thinking.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/tools.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/renderers/user_input.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/cjk_wrap.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/code_panel.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/live.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/markdown.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/quote.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/searchable_text.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/status.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/rich/theme.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/terminal/__init__.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/terminal/color.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/terminal/control.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/terminal/notifier.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/terminal/progress_bar.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/terminal/selector.py +0 -0
- {klaude_code-1.6.0 → klaude_code-1.7.0}/src/klaude_code/ui/utils/__init__.py +0 -0
- {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.
|
|
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
|
-
- `/
|
|
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
|
-
- `/
|
|
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.
|
|
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=
|
|
172
|
-
models_table.add_column(overflow="fold", ratio=
|
|
173
|
-
models_table.add_column(overflow="fold", ratio=
|
|
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
|
-
|
|
26
|
-
|
|
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}
|
|
@@ -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}")
|