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.
- klaude_code/auth/base.py +2 -6
- klaude_code/cli/auth_cmd.py +4 -4
- klaude_code/cli/cost_cmd.py +1 -1
- klaude_code/cli/list_model.py +1 -1
- klaude_code/cli/main.py +1 -1
- klaude_code/cli/runtime.py +7 -5
- klaude_code/cli/self_update.py +1 -1
- klaude_code/cli/session_cmd.py +1 -1
- klaude_code/command/clear_cmd.py +6 -2
- klaude_code/command/command_abc.py +2 -2
- klaude_code/command/debug_cmd.py +4 -4
- klaude_code/command/export_cmd.py +2 -2
- klaude_code/command/export_online_cmd.py +12 -12
- klaude_code/command/fork_session_cmd.py +29 -23
- klaude_code/command/help_cmd.py +4 -4
- klaude_code/command/model_cmd.py +4 -4
- klaude_code/command/model_select.py +1 -1
- klaude_code/command/prompt-commit.md +11 -2
- klaude_code/command/prompt_command.py +3 -3
- klaude_code/command/refresh_cmd.py +2 -2
- klaude_code/command/registry.py +7 -5
- klaude_code/command/release_notes_cmd.py +4 -4
- klaude_code/command/resume_cmd.py +15 -11
- klaude_code/command/status_cmd.py +4 -4
- klaude_code/command/terminal_setup_cmd.py +8 -8
- klaude_code/command/thinking_cmd.py +4 -4
- klaude_code/config/assets/builtin_config.yaml +20 -0
- klaude_code/config/builtin_config.py +16 -5
- klaude_code/config/config.py +7 -2
- klaude_code/const.py +147 -91
- klaude_code/core/agent.py +3 -12
- klaude_code/core/executor.py +18 -39
- klaude_code/core/manager/sub_agent_manager.py +71 -7
- klaude_code/core/prompts/prompt-sub-agent-image-gen.md +1 -0
- klaude_code/core/prompts/prompt-sub-agent-web.md +27 -1
- klaude_code/core/reminders.py +88 -69
- klaude_code/core/task.py +44 -45
- klaude_code/core/tool/file/apply_patch_tool.py +9 -9
- klaude_code/core/tool/file/diff_builder.py +3 -5
- klaude_code/core/tool/file/edit_tool.py +23 -23
- klaude_code/core/tool/file/move_tool.py +43 -43
- klaude_code/core/tool/file/read_tool.py +44 -39
- klaude_code/core/tool/file/write_tool.py +14 -14
- klaude_code/core/tool/report_back_tool.py +4 -4
- klaude_code/core/tool/shell/bash_tool.py +23 -23
- klaude_code/core/tool/skill/skill_tool.py +7 -7
- klaude_code/core/tool/sub_agent_tool.py +38 -9
- klaude_code/core/tool/todo/todo_write_tool.py +9 -10
- klaude_code/core/tool/todo/update_plan_tool.py +6 -6
- klaude_code/core/tool/tool_abc.py +2 -2
- klaude_code/core/tool/tool_context.py +27 -0
- klaude_code/core/tool/tool_runner.py +88 -42
- klaude_code/core/tool/truncation.py +38 -20
- klaude_code/core/tool/web/mermaid_tool.py +6 -7
- klaude_code/core/tool/web/web_fetch_tool.py +68 -30
- klaude_code/core/tool/web/web_search_tool.py +15 -17
- klaude_code/core/turn.py +120 -73
- klaude_code/llm/anthropic/client.py +79 -44
- klaude_code/llm/anthropic/input.py +116 -108
- klaude_code/llm/bedrock/client.py +8 -5
- klaude_code/llm/claude/client.py +18 -8
- klaude_code/llm/client.py +4 -3
- klaude_code/llm/codex/client.py +15 -9
- klaude_code/llm/google/client.py +122 -60
- klaude_code/llm/google/input.py +94 -108
- klaude_code/llm/image.py +123 -0
- klaude_code/llm/input_common.py +136 -189
- klaude_code/llm/openai_compatible/client.py +17 -7
- klaude_code/llm/openai_compatible/input.py +36 -66
- klaude_code/llm/openai_compatible/stream.py +119 -67
- klaude_code/llm/openai_compatible/tool_call_accumulator.py +23 -11
- klaude_code/llm/openrouter/client.py +34 -9
- klaude_code/llm/openrouter/input.py +63 -64
- klaude_code/llm/openrouter/reasoning.py +22 -24
- klaude_code/llm/registry.py +20 -17
- klaude_code/llm/responses/client.py +107 -45
- klaude_code/llm/responses/input.py +115 -98
- klaude_code/llm/usage.py +52 -25
- klaude_code/protocol/__init__.py +1 -0
- klaude_code/protocol/events.py +16 -12
- klaude_code/protocol/llm_param.py +20 -2
- klaude_code/protocol/message.py +250 -0
- klaude_code/protocol/model.py +95 -285
- klaude_code/protocol/op.py +2 -15
- klaude_code/protocol/op_handler.py +0 -5
- klaude_code/protocol/sub_agent/__init__.py +1 -0
- klaude_code/protocol/sub_agent/explore.py +10 -0
- klaude_code/protocol/sub_agent/image_gen.py +119 -0
- klaude_code/protocol/sub_agent/task.py +10 -0
- klaude_code/protocol/sub_agent/web.py +10 -0
- klaude_code/session/codec.py +6 -6
- klaude_code/session/export.py +261 -62
- klaude_code/session/selector.py +7 -24
- klaude_code/session/session.py +126 -54
- klaude_code/session/store.py +5 -32
- klaude_code/session/templates/export_session.html +1 -1
- klaude_code/session/templates/mermaid_viewer.html +1 -1
- klaude_code/trace/log.py +11 -6
- klaude_code/ui/core/input.py +1 -1
- klaude_code/ui/core/stage_manager.py +1 -8
- klaude_code/ui/modes/debug/display.py +2 -2
- klaude_code/ui/modes/repl/clipboard.py +2 -2
- klaude_code/ui/modes/repl/completers.py +18 -10
- klaude_code/ui/modes/repl/event_handler.py +138 -132
- klaude_code/ui/modes/repl/input_prompt_toolkit.py +1 -1
- klaude_code/ui/modes/repl/key_bindings.py +136 -2
- klaude_code/ui/modes/repl/renderer.py +107 -15
- klaude_code/ui/renderers/assistant.py +2 -2
- klaude_code/ui/renderers/bash_syntax.py +36 -4
- klaude_code/ui/renderers/common.py +70 -10
- klaude_code/ui/renderers/developer.py +7 -6
- klaude_code/ui/renderers/diffs.py +11 -11
- klaude_code/ui/renderers/mermaid_viewer.py +49 -2
- klaude_code/ui/renderers/metadata.py +33 -5
- klaude_code/ui/renderers/sub_agent.py +57 -16
- klaude_code/ui/renderers/thinking.py +37 -2
- klaude_code/ui/renderers/tools.py +188 -178
- klaude_code/ui/rich/live.py +3 -1
- klaude_code/ui/rich/markdown.py +39 -7
- klaude_code/ui/rich/quote.py +76 -1
- klaude_code/ui/rich/status.py +14 -8
- klaude_code/ui/rich/theme.py +20 -14
- klaude_code/ui/terminal/image.py +34 -0
- klaude_code/ui/terminal/notifier.py +2 -1
- klaude_code/ui/terminal/progress_bar.py +4 -4
- klaude_code/ui/terminal/selector.py +22 -4
- klaude_code/ui/utils/common.py +11 -2
- {klaude_code-1.9.0.dist-info → klaude_code-2.0.1.dist-info}/METADATA +4 -2
- klaude_code-2.0.1.dist-info/RECORD +229 -0
- klaude_code-1.9.0.dist-info/RECORD +0 -224
- {klaude_code-1.9.0.dist-info → klaude_code-2.0.1.dist-info}/WHEEL +0 -0
- {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
|
|
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
|
-
|
|
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) >
|
|
101
|
-
hidden_count = len(lines) -
|
|
102
|
-
head_count =
|
|
103
|
-
tail_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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
93
|
+
(0, MARKDOWN_RIGHT_MARGIN, 0, 0),
|
|
59
94
|
),
|
|
60
95
|
)
|
|
61
96
|
return grid
|