klaude-code 1.2.6__py3-none-any.whl → 1.8.0__py3-none-any.whl

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 (205) hide show
  1. klaude_code/auth/__init__.py +24 -0
  2. klaude_code/auth/codex/__init__.py +20 -0
  3. klaude_code/auth/codex/exceptions.py +17 -0
  4. klaude_code/auth/codex/jwt_utils.py +45 -0
  5. klaude_code/auth/codex/oauth.py +229 -0
  6. klaude_code/auth/codex/token_manager.py +84 -0
  7. klaude_code/cli/auth_cmd.py +73 -0
  8. klaude_code/cli/config_cmd.py +91 -0
  9. klaude_code/cli/cost_cmd.py +338 -0
  10. klaude_code/cli/debug.py +78 -0
  11. klaude_code/cli/list_model.py +307 -0
  12. klaude_code/cli/main.py +233 -134
  13. klaude_code/cli/runtime.py +309 -117
  14. klaude_code/{version.py → cli/self_update.py} +114 -5
  15. klaude_code/cli/session_cmd.py +37 -21
  16. klaude_code/command/__init__.py +88 -27
  17. klaude_code/command/clear_cmd.py +8 -7
  18. klaude_code/command/command_abc.py +31 -31
  19. klaude_code/command/debug_cmd.py +79 -0
  20. klaude_code/command/export_cmd.py +19 -53
  21. klaude_code/command/export_online_cmd.py +154 -0
  22. klaude_code/command/fork_session_cmd.py +267 -0
  23. klaude_code/command/help_cmd.py +7 -8
  24. klaude_code/command/model_cmd.py +60 -10
  25. klaude_code/command/model_select.py +84 -0
  26. klaude_code/command/prompt-jj-describe.md +32 -0
  27. klaude_code/command/prompt_command.py +19 -11
  28. klaude_code/command/refresh_cmd.py +8 -10
  29. klaude_code/command/registry.py +139 -40
  30. klaude_code/command/release_notes_cmd.py +84 -0
  31. klaude_code/command/resume_cmd.py +111 -0
  32. klaude_code/command/status_cmd.py +104 -60
  33. klaude_code/command/terminal_setup_cmd.py +7 -9
  34. klaude_code/command/thinking_cmd.py +98 -0
  35. klaude_code/config/__init__.py +14 -6
  36. klaude_code/config/assets/__init__.py +1 -0
  37. klaude_code/config/assets/builtin_config.yaml +303 -0
  38. klaude_code/config/builtin_config.py +38 -0
  39. klaude_code/config/config.py +378 -109
  40. klaude_code/config/select_model.py +117 -53
  41. klaude_code/config/thinking.py +269 -0
  42. klaude_code/{const/__init__.py → const.py} +50 -19
  43. klaude_code/core/agent.py +20 -28
  44. klaude_code/core/executor.py +327 -112
  45. klaude_code/core/manager/__init__.py +2 -4
  46. klaude_code/core/manager/llm_clients.py +1 -15
  47. klaude_code/core/manager/llm_clients_builder.py +10 -11
  48. klaude_code/core/manager/sub_agent_manager.py +37 -6
  49. klaude_code/core/prompt.py +63 -44
  50. klaude_code/core/prompts/prompt-claude-code.md +2 -13
  51. klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +117 -0
  52. klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +117 -0
  53. klaude_code/core/prompts/prompt-codex.md +9 -42
  54. klaude_code/core/prompts/prompt-minimal.md +12 -0
  55. klaude_code/core/prompts/{prompt-subagent-explore.md → prompt-sub-agent-explore.md} +16 -3
  56. klaude_code/core/prompts/{prompt-subagent-oracle.md → prompt-sub-agent-oracle.md} +1 -2
  57. klaude_code/core/prompts/prompt-sub-agent-web.md +51 -0
  58. klaude_code/core/reminders.py +283 -95
  59. klaude_code/core/task.py +113 -75
  60. klaude_code/core/tool/__init__.py +24 -31
  61. klaude_code/core/tool/file/_utils.py +36 -0
  62. klaude_code/core/tool/file/apply_patch.py +17 -25
  63. klaude_code/core/tool/file/apply_patch_tool.py +57 -77
  64. klaude_code/core/tool/file/diff_builder.py +151 -0
  65. klaude_code/core/tool/file/edit_tool.py +50 -63
  66. klaude_code/core/tool/file/move_tool.md +41 -0
  67. klaude_code/core/tool/file/move_tool.py +435 -0
  68. klaude_code/core/tool/file/read_tool.md +1 -1
  69. klaude_code/core/tool/file/read_tool.py +86 -86
  70. klaude_code/core/tool/file/write_tool.py +59 -69
  71. klaude_code/core/tool/report_back_tool.py +84 -0
  72. klaude_code/core/tool/shell/bash_tool.py +265 -22
  73. klaude_code/core/tool/shell/command_safety.py +3 -6
  74. klaude_code/core/tool/{memory → skill}/skill_tool.py +16 -26
  75. klaude_code/core/tool/sub_agent_tool.py +13 -2
  76. klaude_code/core/tool/todo/todo_write_tool.md +0 -157
  77. klaude_code/core/tool/todo/todo_write_tool.py +1 -1
  78. klaude_code/core/tool/todo/todo_write_tool_raw.md +182 -0
  79. klaude_code/core/tool/todo/update_plan_tool.py +1 -1
  80. klaude_code/core/tool/tool_abc.py +18 -0
  81. klaude_code/core/tool/tool_context.py +27 -12
  82. klaude_code/core/tool/tool_registry.py +7 -7
  83. klaude_code/core/tool/tool_runner.py +44 -36
  84. klaude_code/core/tool/truncation.py +29 -14
  85. klaude_code/core/tool/web/mermaid_tool.md +43 -0
  86. klaude_code/core/tool/web/mermaid_tool.py +2 -5
  87. klaude_code/core/tool/web/web_fetch_tool.md +1 -1
  88. klaude_code/core/tool/web/web_fetch_tool.py +112 -22
  89. klaude_code/core/tool/web/web_search_tool.md +23 -0
  90. klaude_code/core/tool/web/web_search_tool.py +130 -0
  91. klaude_code/core/turn.py +168 -66
  92. klaude_code/llm/__init__.py +2 -10
  93. klaude_code/llm/anthropic/client.py +190 -178
  94. klaude_code/llm/anthropic/input.py +39 -15
  95. klaude_code/llm/bedrock/__init__.py +3 -0
  96. klaude_code/llm/bedrock/client.py +60 -0
  97. klaude_code/llm/client.py +7 -21
  98. klaude_code/llm/codex/__init__.py +5 -0
  99. klaude_code/llm/codex/client.py +149 -0
  100. klaude_code/llm/google/__init__.py +3 -0
  101. klaude_code/llm/google/client.py +309 -0
  102. klaude_code/llm/google/input.py +215 -0
  103. klaude_code/llm/input_common.py +3 -9
  104. klaude_code/llm/openai_compatible/client.py +72 -164
  105. klaude_code/llm/openai_compatible/input.py +6 -4
  106. klaude_code/llm/openai_compatible/stream.py +273 -0
  107. klaude_code/llm/openai_compatible/tool_call_accumulator.py +17 -1
  108. klaude_code/llm/openrouter/client.py +89 -160
  109. klaude_code/llm/openrouter/input.py +18 -30
  110. klaude_code/llm/openrouter/reasoning.py +118 -0
  111. klaude_code/llm/registry.py +39 -7
  112. klaude_code/llm/responses/client.py +184 -171
  113. klaude_code/llm/responses/input.py +20 -1
  114. klaude_code/llm/usage.py +17 -12
  115. klaude_code/protocol/commands.py +17 -1
  116. klaude_code/protocol/events.py +31 -4
  117. klaude_code/protocol/llm_param.py +13 -10
  118. klaude_code/protocol/model.py +232 -29
  119. klaude_code/protocol/op.py +90 -1
  120. klaude_code/protocol/op_handler.py +35 -1
  121. klaude_code/protocol/sub_agent/__init__.py +117 -0
  122. klaude_code/protocol/sub_agent/explore.py +63 -0
  123. klaude_code/protocol/sub_agent/oracle.py +91 -0
  124. klaude_code/protocol/sub_agent/task.py +61 -0
  125. klaude_code/protocol/sub_agent/web.py +79 -0
  126. klaude_code/protocol/tools.py +4 -2
  127. klaude_code/session/__init__.py +2 -2
  128. klaude_code/session/codec.py +71 -0
  129. klaude_code/session/export.py +293 -86
  130. klaude_code/session/selector.py +89 -67
  131. klaude_code/session/session.py +320 -309
  132. klaude_code/session/store.py +220 -0
  133. klaude_code/session/templates/export_session.html +595 -83
  134. klaude_code/session/templates/mermaid_viewer.html +926 -0
  135. klaude_code/skill/__init__.py +27 -0
  136. klaude_code/skill/assets/deslop/SKILL.md +17 -0
  137. klaude_code/skill/assets/dev-docs/SKILL.md +108 -0
  138. klaude_code/skill/assets/handoff/SKILL.md +39 -0
  139. klaude_code/skill/assets/jj-workspace/SKILL.md +20 -0
  140. klaude_code/skill/assets/skill-creator/SKILL.md +139 -0
  141. klaude_code/{core/tool/memory/skill_loader.py → skill/loader.py} +55 -15
  142. klaude_code/skill/manager.py +70 -0
  143. klaude_code/skill/system_skills.py +192 -0
  144. klaude_code/trace/__init__.py +20 -2
  145. klaude_code/trace/log.py +150 -5
  146. klaude_code/ui/__init__.py +4 -9
  147. klaude_code/ui/core/input.py +1 -1
  148. klaude_code/ui/core/stage_manager.py +7 -7
  149. klaude_code/ui/modes/debug/display.py +2 -1
  150. klaude_code/ui/modes/repl/__init__.py +3 -48
  151. klaude_code/ui/modes/repl/clipboard.py +5 -5
  152. klaude_code/ui/modes/repl/completers.py +487 -123
  153. klaude_code/ui/modes/repl/display.py +5 -4
  154. klaude_code/ui/modes/repl/event_handler.py +370 -117
  155. klaude_code/ui/modes/repl/input_prompt_toolkit.py +552 -105
  156. klaude_code/ui/modes/repl/key_bindings.py +146 -23
  157. klaude_code/ui/modes/repl/renderer.py +189 -99
  158. klaude_code/ui/renderers/assistant.py +9 -2
  159. klaude_code/ui/renderers/bash_syntax.py +178 -0
  160. klaude_code/ui/renderers/common.py +78 -0
  161. klaude_code/ui/renderers/developer.py +104 -48
  162. klaude_code/ui/renderers/diffs.py +87 -6
  163. klaude_code/ui/renderers/errors.py +11 -6
  164. klaude_code/ui/renderers/mermaid_viewer.py +57 -0
  165. klaude_code/ui/renderers/metadata.py +112 -76
  166. klaude_code/ui/renderers/sub_agent.py +92 -7
  167. klaude_code/ui/renderers/thinking.py +40 -18
  168. klaude_code/ui/renderers/tools.py +405 -227
  169. klaude_code/ui/renderers/user_input.py +73 -13
  170. klaude_code/ui/rich/__init__.py +10 -1
  171. klaude_code/ui/rich/cjk_wrap.py +228 -0
  172. klaude_code/ui/rich/code_panel.py +131 -0
  173. klaude_code/ui/rich/live.py +17 -0
  174. klaude_code/ui/rich/markdown.py +305 -170
  175. klaude_code/ui/rich/searchable_text.py +10 -13
  176. klaude_code/ui/rich/status.py +190 -49
  177. klaude_code/ui/rich/theme.py +135 -39
  178. klaude_code/ui/terminal/__init__.py +55 -0
  179. klaude_code/ui/terminal/color.py +1 -1
  180. klaude_code/ui/terminal/control.py +13 -22
  181. klaude_code/ui/terminal/notifier.py +44 -4
  182. klaude_code/ui/terminal/selector.py +658 -0
  183. klaude_code/ui/utils/common.py +0 -18
  184. klaude_code-1.8.0.dist-info/METADATA +377 -0
  185. klaude_code-1.8.0.dist-info/RECORD +219 -0
  186. {klaude_code-1.2.6.dist-info → klaude_code-1.8.0.dist-info}/entry_points.txt +1 -0
  187. klaude_code/command/diff_cmd.py +0 -138
  188. klaude_code/command/prompt-dev-docs-update.md +0 -56
  189. klaude_code/command/prompt-dev-docs.md +0 -46
  190. klaude_code/config/list_model.py +0 -162
  191. klaude_code/core/manager/agent_manager.py +0 -127
  192. klaude_code/core/prompts/prompt-subagent-webfetch.md +0 -46
  193. klaude_code/core/tool/file/multi_edit_tool.md +0 -42
  194. klaude_code/core/tool/file/multi_edit_tool.py +0 -199
  195. klaude_code/core/tool/memory/memory_tool.md +0 -16
  196. klaude_code/core/tool/memory/memory_tool.py +0 -462
  197. klaude_code/llm/openrouter/reasoning_handler.py +0 -209
  198. klaude_code/protocol/sub_agent.py +0 -348
  199. klaude_code/ui/utils/debouncer.py +0 -42
  200. klaude_code-1.2.6.dist-info/METADATA +0 -178
  201. klaude_code-1.2.6.dist-info/RECORD +0 -167
  202. /klaude_code/core/prompts/{prompt-subagent.md → prompt-sub-agent.md} +0 -0
  203. /klaude_code/core/tool/{memory → skill}/__init__.py +0 -0
  204. /klaude_code/core/tool/{memory → skill}/skill_tool.md +0 -0
  205. {klaude_code-1.2.6.dist-info → klaude_code-1.8.0.dist-info}/WHEEL +0 -0
@@ -1,138 +0,0 @@
1
- import subprocess
2
- from pathlib import Path
3
-
4
- from klaude_code.command.command_abc import CommandABC, CommandResult
5
- from klaude_code.command.registry import register_command
6
- from klaude_code.core.agent import Agent
7
- from klaude_code.protocol import commands, events, model
8
-
9
-
10
- @register_command
11
- class DiffCommand(CommandABC):
12
- """Show git diff for the current repository."""
13
-
14
- @property
15
- def name(self) -> commands.CommandName:
16
- return commands.CommandName.DIFF
17
-
18
- @property
19
- def summary(self) -> str:
20
- return "Show git diff"
21
-
22
- async def run(self, raw: str, agent: Agent) -> CommandResult:
23
- try:
24
- # Check if current directory is in a git repository
25
- git_check = subprocess.run(
26
- ["git", "rev-parse", "--is-inside-work-tree"],
27
- cwd=Path.cwd(),
28
- capture_output=True,
29
- text=True,
30
- timeout=5.0,
31
- )
32
-
33
- if git_check.returncode != 0:
34
- # Not in a git repository
35
- event = events.DeveloperMessageEvent(
36
- session_id=agent.session.id,
37
- item=model.DeveloperMessageItem(
38
- content="No in a git repo",
39
- command_output=model.CommandOutput(command_name=self.name, is_error=True),
40
- ),
41
- )
42
- return CommandResult(events=[event])
43
-
44
- # Run git diff in current directory
45
- result = subprocess.run(
46
- ["git", "diff", "HEAD"],
47
- cwd=Path.cwd(),
48
- capture_output=True,
49
- text=True,
50
- timeout=10.0,
51
- )
52
-
53
- if result.returncode != 0:
54
- # Git command failed
55
- error_msg = result.stderr.strip() or "git diff command failed"
56
- event = events.DeveloperMessageEvent(
57
- session_id=agent.session.id,
58
- item=model.DeveloperMessageItem(
59
- content=f"Error: {error_msg}",
60
- command_output=model.CommandOutput(command_name=self.name, is_error=True),
61
- ),
62
- )
63
- return CommandResult(events=[event])
64
-
65
- diff_output = result.stdout.strip()
66
-
67
- # Get untracked files
68
- untracked_result = subprocess.run(
69
- ["git", "ls-files", "--others", "--exclude-standard"],
70
- cwd=Path.cwd(),
71
- capture_output=True,
72
- text=True,
73
- timeout=10.0,
74
- )
75
-
76
- untracked_files = untracked_result.stdout.strip()
77
-
78
- # Combine diff output and untracked files
79
- output_parts: list[str] = []
80
-
81
- if diff_output:
82
- output_parts.append(diff_output)
83
-
84
- if untracked_files:
85
- untracked_lines = untracked_files.split("\n")
86
- untracked_section = "git ls-files --others --exclude-standard\n" + "\n".join(
87
- f"{file}" for file in untracked_lines
88
- )
89
- output_parts.append(untracked_section)
90
-
91
- if not output_parts:
92
- # No changes and no untracked files
93
- event = events.DeveloperMessageEvent(
94
- session_id=agent.session.id,
95
- item=model.DeveloperMessageItem(
96
- content="", command_output=model.CommandOutput(command_name=self.name)
97
- ),
98
- )
99
- return CommandResult(events=[event])
100
-
101
- # Has changes or untracked files
102
- combined_output = "\n\n".join(output_parts)
103
- event = events.DeveloperMessageEvent(
104
- session_id=agent.session.id,
105
- item=model.DeveloperMessageItem(
106
- content=combined_output,
107
- command_output=model.CommandOutput(command_name=self.name),
108
- ),
109
- )
110
- return CommandResult(events=[event])
111
-
112
- except subprocess.TimeoutExpired:
113
- event = events.DeveloperMessageEvent(
114
- session_id=agent.session.id,
115
- item=model.DeveloperMessageItem(
116
- content="Error: git diff command timeout",
117
- command_output=model.CommandOutput(command_name=self.name, is_error=True),
118
- ),
119
- )
120
- return CommandResult(events=[event])
121
- except FileNotFoundError:
122
- event = events.DeveloperMessageEvent(
123
- session_id=agent.session.id,
124
- item=model.DeveloperMessageItem(
125
- content="Error: git command not found",
126
- command_output=model.CommandOutput(command_name=self.name, is_error=True),
127
- ),
128
- )
129
- return CommandResult(events=[event])
130
- except Exception as e:
131
- event = events.DeveloperMessageEvent(
132
- session_id=agent.session.id,
133
- item=model.DeveloperMessageItem(
134
- content=f"Error:{e}",
135
- command_output=model.CommandOutput(command_name=self.name, is_error=True),
136
- ),
137
- )
138
- return CommandResult(events=[event])
@@ -1,56 +0,0 @@
1
- ---
2
- description: Update dev documentation before context compaction
3
- from: https://github.com/diet103/claude-code-infrastructure-showcase/blob/main/.claude/commands/dev-docs-update.md
4
- ---
5
-
6
- We're approaching context limits. Please update the development documentation to ensure seamless continuation after context reset.
7
-
8
- ## Required Updates
9
-
10
- ### 1. Update Active Task Documentation
11
- For each task in `/dev/active/`:
12
- - Update `[task-name]-context.md` with:
13
- - Current implementation state
14
- - Key decisions made this session
15
- - Files modified and why
16
- - Any blockers or issues discovered
17
- - Next immediate steps
18
- - Last Updated timestamp
19
-
20
- - Update `[task-name]-tasks.md` with:
21
- - Mark completed tasks as ✅
22
- - Add any new tasks discovered
23
- - Update in-progress tasks with current status
24
- - Reorder priorities if needed
25
-
26
- ### 2. Capture Session Context
27
- Include any relevant information about:
28
- - Complex problems solved
29
- - Architectural decisions made
30
- - Tricky bugs found and fixed
31
- - Integration points discovered
32
- - Testing approaches used
33
- - Performance optimizations made
34
-
35
- ### 3. Update Memory (if applicable)
36
- - Store any new patterns or solutions in project memory/documentation
37
- - Update entity relationships discovered
38
- - Add observations about system behavior
39
-
40
- ### 4. Document Unfinished Work
41
- - What was being worked on when context limit approached
42
- - Exact state of any partially completed features
43
- - Commands that need to be run on restart
44
- - Any temporary workarounds that need permanent fixes
45
-
46
- ### 5. Create Handoff Notes
47
- If switching to a new conversation:
48
- - Exact file and line being edited
49
- - The goal of current changes
50
- - Any uncommitted changes that need attention
51
- - Test commands to verify work
52
-
53
- ## Additional Context:
54
- $ARGUMENTS
55
-
56
- **Priority**: Focus on capturing information that would be hard to rediscover or reconstruct from code alone.
@@ -1,46 +0,0 @@
1
- ---
2
- description: Create a comprehensive strategic plan with structured task breakdown
3
- from: https://github.com/diet103/claude-code-infrastructure-showcase/blob/main/.claude/commands/dev-docs.md
4
- ---
5
-
6
- Create a comprehensive, actionable plan for:
7
- $ARGUMENTS
8
-
9
- ## Instructions
10
-
11
- 1. **Analyze the request** and determine the scope of planning needed
12
- 2. **Examine relevant files** in the codebase to understand current state
13
- 3. **Create a structured plan** with:
14
- - Executive Summary
15
- - Current State Analysis
16
- - Proposed Future State
17
- - Implementation Phases (broken into sections)
18
- - Detailed Tasks (actionable items with clear acceptance criteria)
19
- - Risk Assessment and Mitigation Strategies
20
- - Success Metrics
21
- - Required Resources and Dependencies
22
- - Timeline Estimates
23
-
24
- 4. **Task Breakdown Structure**:
25
- - Each major section represents a phase or component
26
- - Number and prioritize tasks within sections
27
- - Include clear acceptance criteria for each task
28
- - Specify dependencies between tasks
29
- - Estimate effort levels (S/M/L/XL)
30
-
31
- 5. **Create task management structure**:
32
- - Create directory: `dev/active/[task-name]/` (relative to project root)
33
- - Generate three files:
34
- - `[task-name]-plan.md` - The comprehensive plan
35
- - `[task-name]-context.md` - Key files, decisions, dependencies
36
- - `[task-name]-tasks.md` - Checklist format for tracking progress
37
- - Include "Last Updated: YYYY-MM-DD" in each file
38
-
39
- 6. **Stop and Consult**: Pause and negotiate the plan with the user.
40
-
41
- ## Quality Standards
42
- - Plans must be self-contained with all necessary context
43
- - Use clear, actionable language
44
- - Include specific technical details where relevant
45
- - Consider both technical and business perspectives
46
- - Account for potential risks and edge cases
@@ -1,162 +0,0 @@
1
- from rich.console import Console, Group
2
- from rich.panel import Panel
3
- from rich.table import Table
4
- from rich.text import Text
5
-
6
- from klaude_code.config import Config
7
- from klaude_code.protocol.sub_agent import iter_sub_agent_profiles
8
- from klaude_code.ui.rich.theme import ThemeKey, get_theme
9
-
10
-
11
- def mask_api_key(api_key: str | None) -> str:
12
- """Mask API key to show only first 6 and last 6 characters with *** in between"""
13
- if not api_key or api_key == "N/A":
14
- return "N/A"
15
-
16
- if len(api_key) <= 12:
17
- return api_key
18
-
19
- return f"{api_key[:6]} … {api_key[-6:]}"
20
-
21
-
22
- def display_models_and_providers(config: Config):
23
- """Display models and providers configuration using rich formatting"""
24
- themes = get_theme(config.theme)
25
- console = Console(theme=themes.app_theme)
26
-
27
- # Display providers section
28
- providers_table = Table.grid(padding=(0, 1), expand=True)
29
- providers_table.add_column(width=2, no_wrap=True) # Status
30
- providers_table.add_column(overflow="fold") # Name
31
- providers_table.add_column(overflow="fold") # Protocol
32
- providers_table.add_column(overflow="fold") # Base URL
33
- providers_table.add_column(overflow="fold") # API Key
34
-
35
- # Add header
36
- providers_table.add_row(
37
- Text("", style="bold"),
38
- Text("Name", style=f"bold {ThemeKey.CONFIG_TABLE_HEADER}"),
39
- Text("Protocol", style=f"bold {ThemeKey.CONFIG_TABLE_HEADER}"),
40
- Text("Base URL", style=f"bold {ThemeKey.CONFIG_TABLE_HEADER}"),
41
- Text("API Key", style=f"bold {ThemeKey.CONFIG_TABLE_HEADER}"),
42
- )
43
-
44
- # Add providers
45
- for provider in config.provider_list:
46
- status = Text("✔", style=f"bold {ThemeKey.CONFIG_STATUS_OK}")
47
- name = Text(provider.provider_name, style=ThemeKey.CONFIG_ITEM_NAME)
48
- protocol = Text(str(provider.protocol.value), style="")
49
- base_url = Text(provider.base_url or "N/A", style="")
50
- api_key = Text(mask_api_key(provider.api_key), style="")
51
-
52
- providers_table.add_row(status, name, protocol, base_url, api_key)
53
-
54
- # Display models section
55
- models_table = Table.grid(padding=(0, 1), expand=True)
56
- models_table.add_column(width=2, no_wrap=True) # Status
57
- models_table.add_column(overflow="fold", ratio=1) # Name
58
- models_table.add_column(overflow="fold", ratio=2) # Model
59
- models_table.add_column(overflow="fold", ratio=2) # Provider
60
- models_table.add_column(overflow="fold", ratio=3) # Params
61
-
62
- # Add header
63
- models_table.add_row(
64
- Text("", style="bold"),
65
- Text("Name", style=f"bold {ThemeKey.CONFIG_TABLE_HEADER}"),
66
- Text("Model", style=f"bold {ThemeKey.CONFIG_TABLE_HEADER}"),
67
- Text("Provider", style=f"bold {ThemeKey.CONFIG_TABLE_HEADER}"),
68
- Text("Params", style=f"bold {ThemeKey.CONFIG_TABLE_HEADER}"),
69
- )
70
-
71
- # Add models
72
- for model in config.model_list:
73
- status = Text("✔", style=f"bold {ThemeKey.CONFIG_STATUS_OK}")
74
- if model.model_name == config.main_model:
75
- status = Text("★", style=f"bold {ThemeKey.CONFIG_STATUS_PRIMARY}") # Mark main model
76
-
77
- name = Text(
78
- model.model_name,
79
- style=ThemeKey.CONFIG_STATUS_PRIMARY
80
- if model.model_name == config.main_model
81
- else ThemeKey.CONFIG_ITEM_NAME,
82
- )
83
- model_name = Text(model.model_params.model or "N/A", style="")
84
- provider = Text(model.provider, style="")
85
- params: list[Text] = []
86
- if model.model_params.thinking:
87
- if model.model_params.thinking.reasoning_effort is not None:
88
- params.append(
89
- Text.assemble(
90
- ("reason-effort", ThemeKey.CONFIG_PARAM_LABEL),
91
- ": ",
92
- model.model_params.thinking.reasoning_effort,
93
- )
94
- )
95
- if model.model_params.thinking.reasoning_summary is not None:
96
- params.append(
97
- Text.assemble(
98
- ("reason-summary", ThemeKey.CONFIG_PARAM_LABEL),
99
- ": ",
100
- model.model_params.thinking.reasoning_summary,
101
- )
102
- )
103
- if model.model_params.thinking.budget_tokens is not None:
104
- params.append(
105
- Text.assemble(
106
- ("thinking-budget-tokens", ThemeKey.CONFIG_PARAM_LABEL),
107
- ": ",
108
- str(model.model_params.thinking.budget_tokens),
109
- )
110
- )
111
- if model.model_params.provider_routing:
112
- params.append(
113
- Text.assemble(
114
- ("provider-routing", ThemeKey.CONFIG_PARAM_LABEL),
115
- ": ",
116
- model.model_params.provider_routing.model_dump_json(exclude_none=True),
117
- )
118
- )
119
- if len(params) == 0:
120
- params.append(Text("N/A", style=ThemeKey.CONFIG_PARAM_LABEL))
121
- models_table.add_row(status, name, model_name, provider, Group(*params))
122
-
123
- # Create panels and display
124
- providers_panel = Panel(
125
- providers_table,
126
- title=Text("Providers Configuration", style="white bold"),
127
- border_style=ThemeKey.CONFIG_PANEL_BORDER,
128
- padding=(0, 1),
129
- title_align="left",
130
- )
131
-
132
- models_panel = Panel(
133
- models_table,
134
- title=Text("Models Configuration", style="white bold"),
135
- border_style=ThemeKey.CONFIG_PANEL_BORDER,
136
- padding=(0, 1),
137
- title_align="left",
138
- )
139
-
140
- console.print(providers_panel)
141
- console.print()
142
- console.print(models_panel)
143
-
144
- # Display main model info
145
- console.print()
146
- console.print(
147
- Text.assemble(
148
- ("Default Model: ", "bold"),
149
- (config.main_model, ThemeKey.CONFIG_STATUS_PRIMARY),
150
- )
151
- )
152
-
153
- for profile in iter_sub_agent_profiles():
154
- sub_model_name = config.subagent_models.get(profile.name)
155
- if not sub_model_name:
156
- continue
157
- console.print(
158
- Text.assemble(
159
- (f"{profile.name} Model: ", "bold"),
160
- (sub_model_name, ThemeKey.CONFIG_STATUS_PRIMARY),
161
- )
162
- )
@@ -1,127 +0,0 @@
1
- """Agent and session manager.
2
-
3
- This module contains :class:`AgentManager`, a helper responsible for
4
- creating and tracking agents per session, applying model changes, and
5
- clearing conversations. It is used by the executor context to keep
6
- agent-related responsibilities separate from operation dispatch.
7
- """
8
-
9
- from __future__ import annotations
10
-
11
- import asyncio
12
-
13
- from klaude_code.config import load_config
14
- from klaude_code.core.agent import Agent, DefaultModelProfileProvider, ModelProfileProvider
15
- from klaude_code.core.manager.llm_clients import LLMClients
16
- from klaude_code.llm.registry import create_llm_client
17
- from klaude_code.protocol import commands, events, model
18
- from klaude_code.session.session import Session
19
- from klaude_code.trace import DebugType, log_debug
20
-
21
-
22
- class AgentManager:
23
- """Manager component that tracks agents and their sessions."""
24
-
25
- def __init__(
26
- self,
27
- event_queue: asyncio.Queue[events.Event],
28
- llm_clients: LLMClients,
29
- model_profile_provider: ModelProfileProvider | None = None,
30
- ) -> None:
31
- self._event_queue: asyncio.Queue[events.Event] = event_queue
32
- self._llm_clients: LLMClients = llm_clients
33
- self._model_profile_provider: ModelProfileProvider = model_profile_provider or DefaultModelProfileProvider()
34
- self._active_agents: dict[str, Agent] = {}
35
-
36
- async def emit_event(self, event: events.Event) -> None:
37
- """Emit an event to the shared event queue."""
38
-
39
- await self._event_queue.put(event)
40
-
41
- async def ensure_agent(self, session_id: str) -> Agent:
42
- """Return an existing agent for the session or create a new one."""
43
-
44
- agent = self._active_agents.get(session_id)
45
- if agent is not None:
46
- return agent
47
-
48
- session = Session.load(session_id)
49
- profile = self._model_profile_provider.build_profile(self._llm_clients.main)
50
- agent = Agent(session=session, profile=profile)
51
-
52
- async for evt in agent.replay_history():
53
- await self.emit_event(evt)
54
-
55
- await self.emit_event(
56
- events.WelcomeEvent(
57
- work_dir=str(session.work_dir),
58
- llm_config=self._llm_clients.main.get_llm_config(),
59
- )
60
- )
61
-
62
- self._active_agents[session_id] = agent
63
- log_debug(
64
- f"Initialized agent for session: {session_id}",
65
- style="cyan",
66
- debug_type=DebugType.EXECUTION,
67
- )
68
- return agent
69
-
70
- async def apply_model_change(self, agent: Agent, model_name: str) -> None:
71
- """Change the model used by an agent and notify the UI."""
72
-
73
- config = load_config()
74
- if config is None:
75
- raise ValueError("Configuration must be initialized before changing model")
76
-
77
- llm_config = config.get_model_config(model_name)
78
- llm_client = create_llm_client(llm_config)
79
- agent.set_model_profile(self._model_profile_provider.build_profile(llm_client))
80
-
81
- developer_item = model.DeveloperMessageItem(
82
- content=f"switched to model: {model_name}",
83
- command_output=model.CommandOutput(command_name=commands.CommandName.MODEL),
84
- )
85
- agent.session.append_history([developer_item])
86
-
87
- await self.emit_event(events.DeveloperMessageEvent(session_id=agent.session.id, item=developer_item))
88
- await self.emit_event(events.WelcomeEvent(llm_config=llm_config, work_dir=str(agent.session.work_dir)))
89
-
90
- async def apply_clear(self, agent: Agent) -> None:
91
- """Start a new conversation for an agent and notify the UI."""
92
-
93
- old_session_id = agent.session.id
94
-
95
- # Create a new session instance to replace the current one
96
- new_session = Session(work_dir=agent.session.work_dir)
97
- new_session.model_name = agent.session.model_name
98
-
99
- # Replace the agent's session with the new one
100
- agent.session = new_session
101
- agent.session.save()
102
-
103
- # Update the active_agents mapping
104
- self._active_agents.pop(old_session_id, None)
105
- self._active_agents[new_session.id] = agent
106
-
107
- developer_item = model.DeveloperMessageItem(
108
- content="started new conversation",
109
- command_output=model.CommandOutput(command_name=commands.CommandName.CLEAR),
110
- )
111
-
112
- await self.emit_event(events.DeveloperMessageEvent(session_id=agent.session.id, item=developer_item))
113
-
114
- def get_active_agent(self, session_id: str) -> Agent | None:
115
- """Return the active agent for a session id if present."""
116
-
117
- return self._active_agents.get(session_id)
118
-
119
- def active_session_ids(self) -> list[str]:
120
- """Return a snapshot list of session ids that currently have agents."""
121
-
122
- return list(self._active_agents.keys())
123
-
124
- def all_active_agents(self) -> dict[str, Agent]:
125
- """Return a snapshot of all active agents keyed by session id."""
126
-
127
- return dict(self._active_agents)
@@ -1,46 +0,0 @@
1
- You are a web content fetching and analysis specialist. Your job is to retrieve content from URLs and extract or analyze information according to the user's instructions.
2
-
3
- Your available tools:
4
- - WebFetch: Fetch content from a URL. HTML pages are automatically converted to Markdown.
5
- - Read: Read files from the filesystem (useful when WebFetch output is truncated and saved to a file)
6
- - Bash: Run shell commands (use `rg` to search through large saved files)
7
-
8
- Workflow:
9
- 1. Use WebFetch to retrieve the URL content
10
- 2. Analyze the content according to the user's prompt
11
- 3. If the output was truncated and saved to a file, use Read or `rg` to search through the full content
12
- 4. If you need information from a linked page, use WebFetch to follow that link
13
- 5. Return a clear, structured summary of your findings
14
-
15
- Guidelines:
16
- - Focus on extracting the specific information requested
17
- - For large pages, prioritize the most relevant sections
18
- - If content is truncated, look for the saved file path in the system reminder and use rg to search it
19
- - Return structured data when appropriate (lists, tables, key-value pairs)
20
- - Be concise but comprehensive in your final response
21
- - Use absolute file paths when referencing saved files
22
- - Avoid using emojis
23
-
24
- Following links:
25
- - If a link on the page seems relevant to answering the question, use WebFetch to follow it
26
- - You can fetch multiple pages in sequence to gather all needed information
27
- - After fetching a link, analyze the content yourself to extract what's needed
28
- - Remember to include any fetched URLs in your Sources section if they were helpful
29
-
30
- Handling truncated content:
31
- When WebFetch output is too large, it will be truncated and the full content saved to a temporary file.
32
- The file path will be shown in a system-reminder tag. Use these approaches to access the full content:
33
- - `rg "pattern" /path/to/file` to search for specific content
34
- - Read tool with offset/limit to read specific sections
35
-
36
- Response format:
37
- Your response should be structured as follows:
38
-
39
- [Your answer to the user's question]
40
-
41
- ## Sources
42
- - [URL 1] (saved to local: /path/to/file if saved)
43
- - [URL 2]
44
- ...
45
-
46
- Only include URLs that actually contributed information to your answer. The main URL is always included. Add any additional URLs you fetched that provided relevant information.
@@ -1,42 +0,0 @@
1
- This is a tool for making multiple edits to a single file in one operation. It is built on top of the Edit tool and allows you to perform multiple find-and-replace operations efficiently. Prefer this tool over the Edit tool when you need to make multiple edits to the same file.
2
-
3
- Before using this tool:
4
-
5
- 1. Use the Read tool to understand the file's contents and context
6
- 2. Verify the directory path is correct
7
-
8
- To make multiple file edits, provide the following:
9
- 1. file_path: The absolute path to the file to modify (must be absolute, not relative)
10
- 2. edits: An array of edit operations to perform, where each edit contains:
11
- - old_string: The text to replace (must match the file contents exactly, including all whitespace and indentation)
12
- - new_string: The edited text to replace the old_string
13
- - replace_all: Replace all occurences of old_string. This parameter is optional and defaults to false.
14
-
15
- IMPORTANT:
16
- - All edits are applied in sequence, in the order they are provided
17
- - Each edit operates on the result of the previous edit
18
- - All edits must be valid for the operation to succeed - if any edit fails, none will be applied
19
- - This tool is ideal when you need to make several changes to different parts of the same file
20
- - For Jupyter notebooks (.ipynb files), use the NotebookEdit instead
21
-
22
- CRITICAL REQUIREMENTS:
23
- 1. All edits follow the same requirements as the single Edit tool
24
- 2. The edits are atomic - either all succeed or none are applied
25
- 3. Plan your edits carefully to avoid conflicts between sequential operations
26
-
27
- WARNING:
28
- - The tool will fail if edits.old_string doesn't match the file contents exactly (including whitespace)
29
- - The tool will fail if edits.old_string and edits.new_string are the same
30
- - Since edits are applied in sequence, ensure that earlier edits don't affect the text that later edits are trying to find
31
-
32
- When making edits:
33
- - Ensure all edits result in idiomatic, correct code
34
- - Do not leave the code in a broken state
35
- - Always use absolute file paths (starting with /)
36
- - Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.
37
- - Use replace_all for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.
38
-
39
- If you want to create a new file, use:
40
- - A new file path, including dir name if needed
41
- - First edit: empty old_string and the new file's contents as new_string
42
- - Subsequent edits: normal edit operations on the created content