klaude-code 1.9.0__py3-none-any.whl → 2.0.1__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 (132) hide show
  1. klaude_code/auth/base.py +2 -6
  2. klaude_code/cli/auth_cmd.py +4 -4
  3. klaude_code/cli/cost_cmd.py +1 -1
  4. klaude_code/cli/list_model.py +1 -1
  5. klaude_code/cli/main.py +1 -1
  6. klaude_code/cli/runtime.py +7 -5
  7. klaude_code/cli/self_update.py +1 -1
  8. klaude_code/cli/session_cmd.py +1 -1
  9. klaude_code/command/clear_cmd.py +6 -2
  10. klaude_code/command/command_abc.py +2 -2
  11. klaude_code/command/debug_cmd.py +4 -4
  12. klaude_code/command/export_cmd.py +2 -2
  13. klaude_code/command/export_online_cmd.py +12 -12
  14. klaude_code/command/fork_session_cmd.py +29 -23
  15. klaude_code/command/help_cmd.py +4 -4
  16. klaude_code/command/model_cmd.py +4 -4
  17. klaude_code/command/model_select.py +1 -1
  18. klaude_code/command/prompt-commit.md +11 -2
  19. klaude_code/command/prompt_command.py +3 -3
  20. klaude_code/command/refresh_cmd.py +2 -2
  21. klaude_code/command/registry.py +7 -5
  22. klaude_code/command/release_notes_cmd.py +4 -4
  23. klaude_code/command/resume_cmd.py +15 -11
  24. klaude_code/command/status_cmd.py +4 -4
  25. klaude_code/command/terminal_setup_cmd.py +8 -8
  26. klaude_code/command/thinking_cmd.py +4 -4
  27. klaude_code/config/assets/builtin_config.yaml +20 -0
  28. klaude_code/config/builtin_config.py +16 -5
  29. klaude_code/config/config.py +7 -2
  30. klaude_code/const.py +147 -91
  31. klaude_code/core/agent.py +3 -12
  32. klaude_code/core/executor.py +18 -39
  33. klaude_code/core/manager/sub_agent_manager.py +71 -7
  34. klaude_code/core/prompts/prompt-sub-agent-image-gen.md +1 -0
  35. klaude_code/core/prompts/prompt-sub-agent-web.md +27 -1
  36. klaude_code/core/reminders.py +88 -69
  37. klaude_code/core/task.py +44 -45
  38. klaude_code/core/tool/file/apply_patch_tool.py +9 -9
  39. klaude_code/core/tool/file/diff_builder.py +3 -5
  40. klaude_code/core/tool/file/edit_tool.py +23 -23
  41. klaude_code/core/tool/file/move_tool.py +43 -43
  42. klaude_code/core/tool/file/read_tool.py +44 -39
  43. klaude_code/core/tool/file/write_tool.py +14 -14
  44. klaude_code/core/tool/report_back_tool.py +4 -4
  45. klaude_code/core/tool/shell/bash_tool.py +23 -23
  46. klaude_code/core/tool/skill/skill_tool.py +7 -7
  47. klaude_code/core/tool/sub_agent_tool.py +38 -9
  48. klaude_code/core/tool/todo/todo_write_tool.py +9 -10
  49. klaude_code/core/tool/todo/update_plan_tool.py +6 -6
  50. klaude_code/core/tool/tool_abc.py +2 -2
  51. klaude_code/core/tool/tool_context.py +27 -0
  52. klaude_code/core/tool/tool_runner.py +88 -42
  53. klaude_code/core/tool/truncation.py +38 -20
  54. klaude_code/core/tool/web/mermaid_tool.py +6 -7
  55. klaude_code/core/tool/web/web_fetch_tool.py +68 -30
  56. klaude_code/core/tool/web/web_search_tool.py +15 -17
  57. klaude_code/core/turn.py +120 -73
  58. klaude_code/llm/anthropic/client.py +79 -44
  59. klaude_code/llm/anthropic/input.py +116 -108
  60. klaude_code/llm/bedrock/client.py +8 -5
  61. klaude_code/llm/claude/client.py +18 -8
  62. klaude_code/llm/client.py +4 -3
  63. klaude_code/llm/codex/client.py +15 -9
  64. klaude_code/llm/google/client.py +122 -60
  65. klaude_code/llm/google/input.py +94 -108
  66. klaude_code/llm/image.py +123 -0
  67. klaude_code/llm/input_common.py +136 -189
  68. klaude_code/llm/openai_compatible/client.py +17 -7
  69. klaude_code/llm/openai_compatible/input.py +36 -66
  70. klaude_code/llm/openai_compatible/stream.py +119 -67
  71. klaude_code/llm/openai_compatible/tool_call_accumulator.py +23 -11
  72. klaude_code/llm/openrouter/client.py +34 -9
  73. klaude_code/llm/openrouter/input.py +63 -64
  74. klaude_code/llm/openrouter/reasoning.py +22 -24
  75. klaude_code/llm/registry.py +20 -17
  76. klaude_code/llm/responses/client.py +107 -45
  77. klaude_code/llm/responses/input.py +115 -98
  78. klaude_code/llm/usage.py +52 -25
  79. klaude_code/protocol/__init__.py +1 -0
  80. klaude_code/protocol/events.py +16 -12
  81. klaude_code/protocol/llm_param.py +20 -2
  82. klaude_code/protocol/message.py +250 -0
  83. klaude_code/protocol/model.py +95 -285
  84. klaude_code/protocol/op.py +2 -15
  85. klaude_code/protocol/op_handler.py +0 -5
  86. klaude_code/protocol/sub_agent/__init__.py +1 -0
  87. klaude_code/protocol/sub_agent/explore.py +10 -0
  88. klaude_code/protocol/sub_agent/image_gen.py +119 -0
  89. klaude_code/protocol/sub_agent/task.py +10 -0
  90. klaude_code/protocol/sub_agent/web.py +10 -0
  91. klaude_code/session/codec.py +6 -6
  92. klaude_code/session/export.py +261 -62
  93. klaude_code/session/selector.py +7 -24
  94. klaude_code/session/session.py +126 -54
  95. klaude_code/session/store.py +5 -32
  96. klaude_code/session/templates/export_session.html +1 -1
  97. klaude_code/session/templates/mermaid_viewer.html +1 -1
  98. klaude_code/trace/log.py +11 -6
  99. klaude_code/ui/core/input.py +1 -1
  100. klaude_code/ui/core/stage_manager.py +1 -8
  101. klaude_code/ui/modes/debug/display.py +2 -2
  102. klaude_code/ui/modes/repl/clipboard.py +2 -2
  103. klaude_code/ui/modes/repl/completers.py +18 -10
  104. klaude_code/ui/modes/repl/event_handler.py +138 -132
  105. klaude_code/ui/modes/repl/input_prompt_toolkit.py +1 -1
  106. klaude_code/ui/modes/repl/key_bindings.py +136 -2
  107. klaude_code/ui/modes/repl/renderer.py +107 -15
  108. klaude_code/ui/renderers/assistant.py +2 -2
  109. klaude_code/ui/renderers/bash_syntax.py +36 -4
  110. klaude_code/ui/renderers/common.py +70 -10
  111. klaude_code/ui/renderers/developer.py +7 -6
  112. klaude_code/ui/renderers/diffs.py +11 -11
  113. klaude_code/ui/renderers/mermaid_viewer.py +49 -2
  114. klaude_code/ui/renderers/metadata.py +33 -5
  115. klaude_code/ui/renderers/sub_agent.py +57 -16
  116. klaude_code/ui/renderers/thinking.py +37 -2
  117. klaude_code/ui/renderers/tools.py +188 -178
  118. klaude_code/ui/rich/live.py +3 -1
  119. klaude_code/ui/rich/markdown.py +39 -7
  120. klaude_code/ui/rich/quote.py +76 -1
  121. klaude_code/ui/rich/status.py +14 -8
  122. klaude_code/ui/rich/theme.py +20 -14
  123. klaude_code/ui/terminal/image.py +34 -0
  124. klaude_code/ui/terminal/notifier.py +2 -1
  125. klaude_code/ui/terminal/progress_bar.py +4 -4
  126. klaude_code/ui/terminal/selector.py +22 -4
  127. klaude_code/ui/utils/common.py +11 -2
  128. {klaude_code-1.9.0.dist-info → klaude_code-2.0.1.dist-info}/METADATA +4 -2
  129. klaude_code-2.0.1.dist-info/RECORD +229 -0
  130. klaude_code-1.9.0.dist-info/RECORD +0 -224
  131. {klaude_code-1.9.0.dist-info → klaude_code-2.0.1.dist-info}/WHEEL +0 -0
  132. {klaude_code-1.9.0.dist-info → klaude_code-2.0.1.dist-info}/entry_points.txt +0 -0
@@ -8,9 +8,10 @@ from rich.panel import Panel
8
8
  from rich.style import Style
9
9
  from rich.text import Text
10
10
 
11
- from klaude_code import const
11
+ from klaude_code.const import SUB_AGENT_RESULT_MAX_LINES
12
12
  from klaude_code.protocol import events, model
13
13
  from klaude_code.protocol.sub_agent import get_sub_agent_profile_by_tool
14
+ from klaude_code.ui.renderers.common import truncate_head
14
15
  from klaude_code.ui.rich.markdown import NoInsetMarkdown
15
16
  from klaude_code.ui.rich.theme import ThemeKey
16
17
 
@@ -46,9 +47,15 @@ def render_sub_agent_call(e: model.SubAgentState, style: Style | None = None) ->
46
47
  f" {e.sub_agent_desc} ",
47
48
  style=Style(color=style.color if style else None, bold=True, reverse=True),
48
49
  )
50
+ resume_note = Text("")
51
+ if e.resume:
52
+ resume_note = Text(
53
+ f" resume:{e.resume[:7]} ",
54
+ style=Style(color=style.color if style else None, dim=True),
55
+ )
49
56
  elements: list[RenderableType] = [
50
- Text.assemble((e.sub_agent_type, ThemeKey.TOOL_NAME), " ", desc),
51
- Text(e.sub_agent_prompt, style=style or ""),
57
+ Text.assemble((e.sub_agent_type, ThemeKey.TOOL_NAME), " ", desc, resume_note),
58
+ truncate_head(e.sub_agent_prompt, base_style=style or "", truncated_style=ThemeKey.STATUS_HINT, max_lines=10),
52
59
  ]
53
60
  if e.output_schema:
54
61
  elements.append(Text("\nExpected Output Format JSON:", style=style or ""))
@@ -58,6 +65,20 @@ def render_sub_agent_call(e: model.SubAgentState, style: Style | None = None) ->
58
65
  return Group(*elements)
59
66
 
60
67
 
68
+ def _extract_agent_id_footer(text: str) -> tuple[str, str | None]:
69
+ """Extract agentId footer from result text if present.
70
+
71
+ Returns (main_content, footer_line) where footer_line is None if not found.
72
+ """
73
+ lines = text.rstrip().splitlines()
74
+ if len(lines) >= 2 and lines[-1].startswith("agentId:"):
75
+ # Check if there's an empty line before the footer
76
+ if lines[-2] == "":
77
+ return "\n".join(lines[:-2]), lines[-1]
78
+ return "\n".join(lines[:-1]), lines[-1]
79
+ return text, None
80
+
81
+
61
82
  def render_sub_agent_result(
62
83
  result: str,
63
84
  *,
@@ -70,6 +91,10 @@ def render_sub_agent_result(
70
91
  stripped_result = result.strip()
71
92
  result_panel_style = panel_style or ThemeKey.SUB_AGENT_RESULT_PANEL
72
93
 
94
+ # Extract agentId footer for separate styling
95
+ main_content, agent_id_footer = _extract_agent_id_footer(stripped_result)
96
+ stripped_result = main_content.strip()
97
+
73
98
  # Use rich JSON for structured output
74
99
  if has_structured_output:
75
100
  try:
@@ -82,6 +107,8 @@ def render_sub_agent_result(
82
107
  ]
83
108
  if description:
84
109
  group_elements.insert(0, NoInsetMarkdown(f"# {description}", code_theme=code_theme, style=style or ""))
110
+ if agent_id_footer:
111
+ group_elements.append(Text(agent_id_footer, style=ThemeKey.SUB_AGENT_FOOTER))
85
112
  return Panel.fit(
86
113
  Group(*group_elements),
87
114
  box=box.SIMPLE,
@@ -92,32 +119,41 @@ def render_sub_agent_result(
92
119
  # Fall back to markdown if not valid JSON
93
120
  pass
94
121
 
122
+ if not stripped_result:
123
+ return Text()
124
+
95
125
  # Add markdown heading if description is provided for non-structured output
96
126
  if description:
97
127
  stripped_result = f"# {description}\n\n{stripped_result}"
98
128
 
99
129
  lines = stripped_result.splitlines()
100
- if len(lines) > const.SUB_AGENT_RESULT_MAX_LINES:
101
- hidden_count = len(lines) - const.SUB_AGENT_RESULT_MAX_LINES
102
- head_count = const.SUB_AGENT_RESULT_MAX_LINES // 2
103
- tail_count = const.SUB_AGENT_RESULT_MAX_LINES - head_count
130
+ if len(lines) > SUB_AGENT_RESULT_MAX_LINES:
131
+ hidden_count = len(lines) - SUB_AGENT_RESULT_MAX_LINES
132
+ head_count = SUB_AGENT_RESULT_MAX_LINES // 2
133
+ tail_count = SUB_AGENT_RESULT_MAX_LINES - head_count
104
134
  head_text = "\n".join(lines[:head_count])
105
135
  tail_text = "\n".join(lines[-tail_count:])
106
- return Panel.fit(
107
- Group(
108
- NoInsetMarkdown(head_text, code_theme=code_theme, style=style or ""),
109
- Text(
110
- f"\n( … more {hidden_count} lines — use /export to view full output )\n",
111
- style=ThemeKey.TOOL_RESULT_TRUNCATED,
112
- ),
113
- NoInsetMarkdown(tail_text, code_theme=code_theme, style=style or ""),
136
+ truncated_elements: list[RenderableType] = [
137
+ NoInsetMarkdown(head_text, code_theme=code_theme, style=style or ""),
138
+ Text(
139
+ f"( … more {hidden_count} lines — use /export to view full output )",
140
+ style=ThemeKey.TOOL_RESULT_TRUNCATED,
114
141
  ),
142
+ NoInsetMarkdown(tail_text, code_theme=code_theme, style=style or ""),
143
+ ]
144
+ if agent_id_footer:
145
+ truncated_elements.append(Text(agent_id_footer, style=ThemeKey.SUB_AGENT_FOOTER))
146
+ return Panel.fit(
147
+ Group(*truncated_elements),
115
148
  box=box.SIMPLE,
116
149
  border_style=ThemeKey.LINES,
117
150
  style=result_panel_style,
118
151
  )
152
+ normal_elements: list[RenderableType] = [NoInsetMarkdown(stripped_result, code_theme=code_theme)]
153
+ if agent_id_footer:
154
+ normal_elements.append(Text(agent_id_footer, style=ThemeKey.SUB_AGENT_FOOTER))
119
155
  return Panel.fit(
120
- NoInsetMarkdown(stripped_result, code_theme=code_theme),
156
+ Group(*normal_elements),
121
157
  box=box.SIMPLE,
122
158
  border_style=ThemeKey.LINES,
123
159
  style=result_panel_style,
@@ -132,6 +168,7 @@ def build_sub_agent_state_from_tool_call(e: events.ToolCallEvent) -> model.SubAg
132
168
  description = profile.name
133
169
  prompt = ""
134
170
  output_schema: dict[str, Any] | None = None
171
+ resume: str | None = None
135
172
  if e.arguments:
136
173
  try:
137
174
  payload: dict[str, object] = json.loads(e.arguments)
@@ -143,6 +180,9 @@ def build_sub_agent_state_from_tool_call(e: events.ToolCallEvent) -> model.SubAg
143
180
  prompt_value = payload.get("prompt") or payload.get("task")
144
181
  if isinstance(prompt_value, str):
145
182
  prompt = prompt_value.strip()
183
+ resume_value = payload.get("resume")
184
+ if isinstance(resume_value, str) and resume_value.strip():
185
+ resume = resume_value.strip()
146
186
  # Extract output_schema if profile supports it
147
187
  if profile.output_schema_arg:
148
188
  schema_value = payload.get(profile.output_schema_arg)
@@ -152,5 +192,6 @@ def build_sub_agent_state_from_tool_call(e: events.ToolCallEvent) -> model.SubAg
152
192
  sub_agent_type=profile.name,
153
193
  sub_agent_desc=description,
154
194
  sub_agent_prompt=prompt,
195
+ resume=resume,
155
196
  output_schema=output_schema,
156
197
  )
@@ -4,7 +4,7 @@ from rich.console import RenderableType
4
4
  from rich.padding import Padding
5
5
  from rich.text import Text
6
6
 
7
- from klaude_code import const
7
+ from klaude_code.const import MARKDOWN_RIGHT_MARGIN
8
8
  from klaude_code.ui.renderers.common import create_grid
9
9
  from klaude_code.ui.rich.markdown import ThinkingMarkdown
10
10
  from klaude_code.ui.rich.theme import ThemeKey
@@ -37,6 +37,41 @@ def normalize_thinking_content(content: str) -> str:
37
37
  return text
38
38
 
39
39
 
40
+ def extract_last_bold_header(text: str) -> str | None:
41
+ """Extract the latest complete bold header ("**…**") from text.
42
+
43
+ We treat a bold segment as a "header" only if it appears at the beginning
44
+ of a line (ignoring leading whitespace). This avoids picking up incidental
45
+ emphasis inside paragraphs.
46
+
47
+ Returns None if no complete bold segment is available yet.
48
+ """
49
+
50
+ last: str | None = None
51
+ i = 0
52
+ while True:
53
+ start = text.find("**", i)
54
+ if start < 0:
55
+ break
56
+
57
+ line_start = text.rfind("\n", 0, start) + 1
58
+ if text[line_start:start].strip():
59
+ i = start + 2
60
+ continue
61
+
62
+ end = text.find("**", start + 2)
63
+ if end < 0:
64
+ break
65
+
66
+ inner = " ".join(text[start + 2 : end].split())
67
+ if inner and "\n" not in inner:
68
+ last = inner
69
+
70
+ i = end + 2
71
+
72
+ return last
73
+
74
+
40
75
  def render_thinking(content: str, *, code_theme: str, style: str) -> RenderableType | None:
41
76
  """Render thinking content as markdown with left mark.
42
77
 
@@ -55,7 +90,7 @@ def render_thinking(content: str, *, code_theme: str, style: str) -> RenderableT
55
90
  code_theme=code_theme,
56
91
  style=style,
57
92
  ),
58
- (0, const.MARKDOWN_RIGHT_MARGIN, 0, 0),
93
+ (0, MARKDOWN_RIGHT_MARGIN, 0, 0),
59
94
  ),
60
95
  )
61
96
  return grid