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
|
@@ -3,7 +3,7 @@ import asyncio
|
|
|
3
3
|
from prompt_toolkit.styles import Style
|
|
4
4
|
|
|
5
5
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
6
|
-
from klaude_code.protocol import commands, events, model, op
|
|
6
|
+
from klaude_code.protocol import commands, events, message, model, op
|
|
7
7
|
from klaude_code.session.selector import build_session_select_options, format_user_messages_display
|
|
8
8
|
from klaude_code.trace import log
|
|
9
9
|
from klaude_code.ui.terminal.selector import SelectItem, select_one
|
|
@@ -35,14 +35,16 @@ def select_session_sync() -> str | None:
|
|
|
35
35
|
display_msgs = format_user_messages_display(opt.user_messages)
|
|
36
36
|
title: list[tuple[str, str]] = []
|
|
37
37
|
title.append(("fg:ansibrightblack", f"{idx:2}. "))
|
|
38
|
-
title.append(
|
|
39
|
-
|
|
40
|
-
)
|
|
41
|
-
|
|
38
|
+
title.append(("class:meta", f"{opt.relative_time} · {opt.messages_count} · {opt.model_name}"))
|
|
39
|
+
title.append(("fg:ansibrightblack dim", f" · {opt.session_id}\n"))
|
|
40
|
+
for i, msg in enumerate(display_msgs):
|
|
41
|
+
is_last = i == len(display_msgs) - 1
|
|
42
42
|
if msg == "⋮":
|
|
43
43
|
title.append(("class:msg", f" {msg}\n"))
|
|
44
44
|
else:
|
|
45
|
-
|
|
45
|
+
prefix = "└─" if is_last else "├─"
|
|
46
|
+
title.append(("fg:ansibrightblack dim", f" {prefix} "))
|
|
47
|
+
title.append(("class:msg", f"{msg}\n"))
|
|
46
48
|
title.append(("", "\n"))
|
|
47
49
|
|
|
48
50
|
search_text = " ".join(opt.user_messages) + f" {opt.model_name} {opt.session_id}"
|
|
@@ -80,14 +82,16 @@ class ResumeCommand(CommandABC):
|
|
|
80
82
|
def is_interactive(self) -> bool:
|
|
81
83
|
return True
|
|
82
84
|
|
|
83
|
-
async def run(self, agent: Agent, user_input:
|
|
85
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
84
86
|
del user_input # unused
|
|
85
87
|
|
|
86
88
|
if agent.session.messages_count > 0:
|
|
87
89
|
event = events.DeveloperMessageEvent(
|
|
88
90
|
session_id=agent.session.id,
|
|
89
|
-
item=
|
|
90
|
-
|
|
91
|
+
item=message.DeveloperMessage(
|
|
92
|
+
parts=message.text_parts_from_str(
|
|
93
|
+
"Cannot resume: current session already has messages. Use `klaude -r` to start a new instance with session selection."
|
|
94
|
+
),
|
|
91
95
|
command_output=model.CommandOutput(command_name=self.name, is_error=True),
|
|
92
96
|
),
|
|
93
97
|
)
|
|
@@ -97,8 +101,8 @@ class ResumeCommand(CommandABC):
|
|
|
97
101
|
if selected_session_id is None:
|
|
98
102
|
event = events.DeveloperMessageEvent(
|
|
99
103
|
session_id=agent.session.id,
|
|
100
|
-
item=
|
|
101
|
-
|
|
104
|
+
item=message.DeveloperMessage(
|
|
105
|
+
parts=message.text_parts_from_str("(no session selected)"),
|
|
102
106
|
command_output=model.CommandOutput(command_name=self.name),
|
|
103
107
|
),
|
|
104
108
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
2
|
-
from klaude_code.protocol import commands, events, model
|
|
2
|
+
from klaude_code.protocol import commands, events, message, model
|
|
3
3
|
from klaude_code.session.session import Session
|
|
4
4
|
|
|
5
5
|
|
|
@@ -132,15 +132,15 @@ class StatusCommand(CommandABC):
|
|
|
132
132
|
def summary(self) -> str:
|
|
133
133
|
return "Show session usage statistics"
|
|
134
134
|
|
|
135
|
-
async def run(self, agent: Agent, user_input:
|
|
135
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
136
136
|
del user_input # unused
|
|
137
137
|
session = agent.session
|
|
138
138
|
aggregated = accumulate_session_usage(session)
|
|
139
139
|
|
|
140
140
|
event = events.DeveloperMessageEvent(
|
|
141
141
|
session_id=session.id,
|
|
142
|
-
item=
|
|
143
|
-
|
|
142
|
+
item=message.DeveloperMessage(
|
|
143
|
+
parts=message.text_parts_from_str(format_status_content(aggregated)),
|
|
144
144
|
command_output=model.CommandOutput(
|
|
145
145
|
command_name=self.name,
|
|
146
146
|
ui_extra=model.SessionStatusUIExtra(
|
|
@@ -3,7 +3,7 @@ import subprocess
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
5
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
6
|
-
from klaude_code.protocol import commands, events, model
|
|
6
|
+
from klaude_code.protocol import commands, events, message, model
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class TerminalSetupCommand(CommandABC):
|
|
@@ -21,7 +21,7 @@ class TerminalSetupCommand(CommandABC):
|
|
|
21
21
|
def is_interactive(self) -> bool:
|
|
22
22
|
return False
|
|
23
23
|
|
|
24
|
-
async def run(self, agent: Agent, user_input:
|
|
24
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
25
25
|
del user_input # unused
|
|
26
26
|
term_program = os.environ.get("TERM_PROGRAM", "").lower()
|
|
27
27
|
|
|
@@ -221,28 +221,28 @@ class TerminalSetupCommand(CommandABC):
|
|
|
221
221
|
|
|
222
222
|
return message
|
|
223
223
|
|
|
224
|
-
def _create_success_result(self, agent: "Agent",
|
|
224
|
+
def _create_success_result(self, agent: "Agent", msg: str) -> CommandResult:
|
|
225
225
|
"""Create success result"""
|
|
226
226
|
return CommandResult(
|
|
227
227
|
events=[
|
|
228
228
|
events.DeveloperMessageEvent(
|
|
229
229
|
session_id=agent.session.id,
|
|
230
|
-
item=
|
|
231
|
-
|
|
230
|
+
item=message.DeveloperMessage(
|
|
231
|
+
parts=message.text_parts_from_str(msg),
|
|
232
232
|
command_output=model.CommandOutput(command_name=self.name, is_error=False),
|
|
233
233
|
),
|
|
234
234
|
)
|
|
235
235
|
]
|
|
236
236
|
)
|
|
237
237
|
|
|
238
|
-
def _create_error_result(self, agent: "Agent",
|
|
238
|
+
def _create_error_result(self, agent: "Agent", msg: str) -> CommandResult:
|
|
239
239
|
"""Create error result"""
|
|
240
240
|
return CommandResult(
|
|
241
241
|
events=[
|
|
242
242
|
events.DeveloperMessageEvent(
|
|
243
243
|
session_id=agent.session.id,
|
|
244
|
-
item=
|
|
245
|
-
|
|
244
|
+
item=message.DeveloperMessage(
|
|
245
|
+
parts=message.text_parts_from_str(msg),
|
|
246
246
|
command_output=model.CommandOutput(command_name=self.name, is_error=True),
|
|
247
247
|
),
|
|
248
248
|
)
|
|
@@ -4,7 +4,7 @@ from prompt_toolkit.styles import Style
|
|
|
4
4
|
|
|
5
5
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
6
6
|
from klaude_code.config.thinking import get_thinking_picker_data, parse_thinking_value
|
|
7
|
-
from klaude_code.protocol import commands, events, llm_param, model, op
|
|
7
|
+
from klaude_code.protocol import commands, events, llm_param, message, model, op
|
|
8
8
|
from klaude_code.ui.terminal.selector import SelectItem, select_one
|
|
9
9
|
|
|
10
10
|
SELECT_STYLE = Style(
|
|
@@ -67,7 +67,7 @@ class ThinkingCommand(CommandABC):
|
|
|
67
67
|
def is_interactive(self) -> bool:
|
|
68
68
|
return True
|
|
69
69
|
|
|
70
|
-
async def run(self, agent: Agent, user_input:
|
|
70
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
71
71
|
del user_input # unused
|
|
72
72
|
if agent.profile is None:
|
|
73
73
|
return CommandResult(events=[])
|
|
@@ -80,8 +80,8 @@ class ThinkingCommand(CommandABC):
|
|
|
80
80
|
events=[
|
|
81
81
|
events.DeveloperMessageEvent(
|
|
82
82
|
session_id=agent.session.id,
|
|
83
|
-
item=
|
|
84
|
-
|
|
83
|
+
item=message.DeveloperMessage(
|
|
84
|
+
parts=message.text_parts_from_str("(no change)"),
|
|
85
85
|
command_output=model.CommandOutput(command_name=self.name),
|
|
86
86
|
),
|
|
87
87
|
)
|
|
@@ -187,6 +187,18 @@ provider_list:
|
|
|
187
187
|
input: 0.5
|
|
188
188
|
output: 3.0
|
|
189
189
|
cache_read: 0.05
|
|
190
|
+
- model_name: nano-banana-pro@or
|
|
191
|
+
model_params:
|
|
192
|
+
model: google/gemini-3-pro-image-preview
|
|
193
|
+
context_limit: 1048576
|
|
194
|
+
modalities:
|
|
195
|
+
- image
|
|
196
|
+
- text
|
|
197
|
+
cost:
|
|
198
|
+
input: 2
|
|
199
|
+
output: 12
|
|
200
|
+
cache_read: 0.2
|
|
201
|
+
image: 120
|
|
190
202
|
- model_name: grok
|
|
191
203
|
model_params:
|
|
192
204
|
model: x-ai/grok-4.1-fast
|
|
@@ -238,6 +250,7 @@ provider_list:
|
|
|
238
250
|
input: 0.5
|
|
239
251
|
output: 3.0
|
|
240
252
|
cache_read: 0.05
|
|
253
|
+
|
|
241
254
|
- provider_name: bedrock
|
|
242
255
|
protocol: bedrock
|
|
243
256
|
aws_access_key: ${AWS_ACCESS_KEY_ID}
|
|
@@ -334,3 +347,10 @@ provider_list:
|
|
|
334
347
|
reasoning_effort: medium
|
|
335
348
|
context_limit: 400000
|
|
336
349
|
max_tokens: 128000
|
|
350
|
+
cost:
|
|
351
|
+
input: 1.75
|
|
352
|
+
output: 14.0
|
|
353
|
+
cache_read: 0.17
|
|
354
|
+
|
|
355
|
+
sub_agent_models:
|
|
356
|
+
ImageGen: nano-banana-pro@or
|
|
@@ -7,7 +7,7 @@ manually configuring providers.
|
|
|
7
7
|
|
|
8
8
|
from functools import lru_cache
|
|
9
9
|
from importlib import resources
|
|
10
|
-
from typing import TYPE_CHECKING
|
|
10
|
+
from typing import TYPE_CHECKING, Any
|
|
11
11
|
|
|
12
12
|
import yaml
|
|
13
13
|
|
|
@@ -26,13 +26,24 @@ SUPPORTED_API_KEY_ENVS = [
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
@lru_cache(maxsize=1)
|
|
29
|
+
def _load_builtin_yaml() -> dict[str, Any]:
|
|
30
|
+
"""Load the built-in config YAML asset."""
|
|
31
|
+
assets = resources.files("klaude_code.config.assets")
|
|
32
|
+
yaml_content = (assets / "builtin_config.yaml").read_text()
|
|
33
|
+
data: dict[str, Any] = yaml.safe_load(yaml_content)
|
|
34
|
+
return data
|
|
35
|
+
|
|
36
|
+
|
|
29
37
|
def get_builtin_provider_configs() -> list["ProviderConfig"]:
|
|
30
38
|
"""Load built-in provider configurations from YAML asset."""
|
|
31
39
|
# Import here to avoid circular import
|
|
32
40
|
from klaude_code.config.config import ProviderConfig
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
yaml_content = (assets / "builtin_config.yaml").read_text()
|
|
36
|
-
data = yaml.safe_load(yaml_content)
|
|
37
|
-
|
|
42
|
+
data = _load_builtin_yaml()
|
|
38
43
|
return [ProviderConfig.model_validate(p) for p in data.get("provider_list", [])]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_builtin_sub_agent_models() -> dict[str, str]:
|
|
47
|
+
"""Load built-in sub agent model mappings from YAML asset."""
|
|
48
|
+
data = _load_builtin_yaml()
|
|
49
|
+
return data.get("sub_agent_models", {})
|
klaude_code/config/config.py
CHANGED
|
@@ -8,7 +8,11 @@ from typing import Any, cast
|
|
|
8
8
|
import yaml
|
|
9
9
|
from pydantic import BaseModel, Field, ValidationError, model_validator
|
|
10
10
|
|
|
11
|
-
from klaude_code.config.builtin_config import
|
|
11
|
+
from klaude_code.config.builtin_config import (
|
|
12
|
+
SUPPORTED_API_KEY_ENVS,
|
|
13
|
+
get_builtin_provider_configs,
|
|
14
|
+
get_builtin_sub_agent_models,
|
|
15
|
+
)
|
|
12
16
|
from klaude_code.protocol import llm_param
|
|
13
17
|
from klaude_code.protocol.sub_agent import iter_sub_agent_profiles
|
|
14
18
|
from klaude_code.trace import log
|
|
@@ -294,7 +298,8 @@ def _get_builtin_config() -> Config:
|
|
|
294
298
|
# Re-validate to ensure compatibility with current ProviderConfig class
|
|
295
299
|
# (needed for tests that may monkeypatch the class)
|
|
296
300
|
providers = [ProviderConfig.model_validate(p.model_dump()) for p in get_builtin_provider_configs()]
|
|
297
|
-
|
|
301
|
+
sub_agent_models = get_builtin_sub_agent_models()
|
|
302
|
+
return Config(provider_list=providers, sub_agent_models=sub_agent_models)
|
|
298
303
|
|
|
299
304
|
|
|
300
305
|
def _merge_provider(builtin: ProviderConfig, user: UserProviderConfig) -> ProviderConfig:
|
klaude_code/const.py
CHANGED
|
@@ -4,7 +4,10 @@ This module consolidates all magic numbers and configuration values
|
|
|
4
4
|
that were previously scattered across the codebase.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
7
9
|
import os
|
|
10
|
+
from dataclasses import dataclass
|
|
8
11
|
from pathlib import Path
|
|
9
12
|
|
|
10
13
|
|
|
@@ -20,145 +23,198 @@ def _get_int_env(name: str, default: int) -> int:
|
|
|
20
23
|
|
|
21
24
|
|
|
22
25
|
# =============================================================================
|
|
23
|
-
# Agent Configuration
|
|
26
|
+
# Agent / LLM Configuration
|
|
24
27
|
# =============================================================================
|
|
25
28
|
|
|
26
|
-
#
|
|
27
|
-
|
|
29
|
+
MAX_FAILED_TURN_RETRIES = 10 # Maximum retry attempts for failed turns
|
|
30
|
+
LLM_HTTP_TIMEOUT_TOTAL = 300.0 # HTTP timeout for LLM API requests (seconds)
|
|
31
|
+
LLM_HTTP_TIMEOUT_CONNECT = 15.0 # HTTP connect timeout (seconds)
|
|
32
|
+
LLM_HTTP_TIMEOUT_READ = 285.0 # HTTP read timeout (seconds)
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
ANTHROPIC_BETA_INTERLEAVED_THINKING = "interleaved-thinking-2025-05-14" # Anthropic API beta flag
|
|
35
|
+
ANTHROPIC_BETA_OAUTH = "oauth-2025-04-20" # Anthropic OAuth beta flag
|
|
36
|
+
ANTHROPIC_BETA_FINE_GRAINED_TOOL_STREAMING = "fine-grained-tool-streaming-2025-05-14" # Anthropic streaming beta
|
|
37
|
+
CLAUDE_CODE_IDENTITY = "You are Claude Code, Anthropic's official CLI for Claude." # Claude identity string
|
|
31
38
|
|
|
32
|
-
|
|
33
|
-
INITIAL_RETRY_DELAY_S = 1.0
|
|
39
|
+
OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1" # OpenRouter API base URL
|
|
34
40
|
|
|
35
|
-
#
|
|
36
|
-
|
|
41
|
+
CODEX_BASE_URL = "https://chatgpt.com/backend-api/codex" # Codex API base URL
|
|
42
|
+
CODEX_USER_AGENT = "codex_cli_rs/0.0.0-klaude" # Codex user agent string
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
CANCEL_OUTPUT = "[Request interrupted by user for tool use]"
|
|
44
|
+
SUPPORTED_IMAGE_SIZES = {"1K", "2K", "4K"} # Supported image sizes for ImageGen tool
|
|
40
45
|
|
|
41
|
-
#
|
|
42
|
-
|
|
46
|
+
THROUGHPUT_MIN_DURATION_SEC = 0.15 # Minimum duration (seconds) for throughput calculation
|
|
47
|
+
INITIAL_RETRY_DELAY_S = 1.0 # Initial delay before retrying a failed turn (seconds)
|
|
48
|
+
MAX_RETRY_DELAY_S = 30.0 # Maximum delay between retries (seconds)
|
|
49
|
+
CANCEL_OUTPUT = "[Request interrupted by user for tool use]" # Message shown when tool call is cancelled
|
|
50
|
+
INTERRUPT_MARKER = " <system>interrupted by user</system>" # Marker appended when assistant is interrupted
|
|
51
|
+
EMPTY_TOOL_OUTPUT_MESSAGE = (
|
|
52
|
+
"<system-reminder>Tool ran without output or errors</system-reminder>" # Tool output placeholder
|
|
53
|
+
)
|
|
54
|
+
DEFAULT_MAX_TOKENS = 32000 # Default maximum tokens for LLM responses
|
|
55
|
+
DEFAULT_TEMPERATURE = 1.0 # Default temperature for LLM requests
|
|
56
|
+
DEFAULT_ANTHROPIC_THINKING_BUDGET_TOKENS = 2048 # Default thinking budget tokens for Anthropic models
|
|
43
57
|
|
|
44
|
-
# Default temperature for LLM requests
|
|
45
|
-
DEFAULT_TEMPERATURE = 1.0
|
|
46
58
|
|
|
47
|
-
#
|
|
48
|
-
|
|
59
|
+
# =============================================================================
|
|
60
|
+
# Reminders
|
|
61
|
+
# =============================================================================
|
|
49
62
|
|
|
50
|
-
# Tool call count threshold for todo reminder
|
|
51
|
-
|
|
63
|
+
TODO_REMINDER_TOOL_CALL_THRESHOLD = 10 # Tool call count threshold for todo reminder
|
|
64
|
+
REMINDER_COOLDOWN_TURNS = 3 # Cooldown turns between reminder triggers
|
|
65
|
+
MEMORY_FILE_NAMES = ["CLAUDE.md", "AGENTS.md", "AGENT.md"] # Memory file names to search for
|
|
52
66
|
|
|
53
67
|
|
|
54
68
|
# =============================================================================
|
|
55
|
-
# Tool
|
|
69
|
+
# Tool - Read
|
|
56
70
|
# =============================================================================
|
|
57
71
|
|
|
58
|
-
#
|
|
59
|
-
# Maximum
|
|
60
|
-
|
|
72
|
+
READ_CHAR_LIMIT_PER_LINE = 2000 # Maximum characters per line before truncation
|
|
73
|
+
READ_GLOBAL_LINE_CAP = _get_int_env("KLAUDE_READ_GLOBAL_LINE_CAP", 2000) # Maximum lines to read from a file
|
|
74
|
+
READ_MAX_CHARS = _get_int_env("KLAUDE_READ_MAX_CHARS", 50000) # Maximum total characters to read
|
|
75
|
+
READ_MAX_IMAGE_BYTES = _get_int_env("KLAUDE_READ_MAX_IMAGE_BYTES", 4 * 1024 * 1024) # Max image size (4MB)
|
|
76
|
+
IMAGE_OUTPUT_MAX_BYTES = _get_int_env("KLAUDE_IMAGE_OUTPUT_MAX_BYTES", 64 * 1024 * 1024) # Max decoded image (64MB)
|
|
77
|
+
BINARY_CHECK_SIZE = 8192 # Bytes to check for binary file detection
|
|
61
78
|
|
|
62
|
-
# Maximum number of lines to read from a file
|
|
63
|
-
# Can be overridden via KLAUDE_READ_GLOBAL_LINE_CAP environment variable
|
|
64
|
-
READ_GLOBAL_LINE_CAP = _get_int_env("KLAUDE_READ_GLOBAL_LINE_CAP", 2000)
|
|
65
79
|
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
|
|
80
|
+
# =============================================================================
|
|
81
|
+
# Tool - Bash / Shell
|
|
82
|
+
# =============================================================================
|
|
69
83
|
|
|
70
|
-
#
|
|
71
|
-
|
|
84
|
+
BASH_DEFAULT_TIMEOUT_MS = 120000 # Default timeout for bash commands (milliseconds)
|
|
85
|
+
BASH_TERMINATE_TIMEOUT_SEC = 1.0 # Timeout before escalating to SIGKILL (seconds)
|
|
72
86
|
|
|
73
|
-
# -- Bash Tool --
|
|
74
|
-
# Default timeout for bash commands (milliseconds)
|
|
75
|
-
BASH_DEFAULT_TIMEOUT_MS = 120000
|
|
76
87
|
|
|
77
|
-
#
|
|
78
|
-
#
|
|
79
|
-
|
|
88
|
+
# =============================================================================
|
|
89
|
+
# Tool - Web
|
|
90
|
+
# =============================================================================
|
|
80
91
|
|
|
81
|
-
|
|
82
|
-
|
|
92
|
+
WEB_FETCH_DEFAULT_TIMEOUT_SEC = 30 # Default timeout for web fetch requests (seconds)
|
|
93
|
+
WEB_FETCH_USER_AGENT = "Mozilla/5.0 (compatible; KlaudeCode/1.0)" # User-Agent header for web requests
|
|
94
|
+
URL_FILENAME_MAX_LENGTH = 80 # Maximum length for extracting filename from URL
|
|
95
|
+
WEB_SEARCH_DEFAULT_MAX_RESULTS = 10 # Default number of search results
|
|
96
|
+
WEB_SEARCH_MAX_RESULTS_LIMIT = 20 # Maximum number of search results allowed
|
|
97
|
+
MERMAID_LIVE_PREFIX = "https://mermaid.live/view#pako:" # Mermaid.live URL prefix
|
|
83
98
|
|
|
84
|
-
# Characters to show from the end of truncated output
|
|
85
|
-
TOOL_OUTPUT_DISPLAY_TAIL = 10000
|
|
86
99
|
|
|
87
|
-
#
|
|
88
|
-
|
|
100
|
+
# =============================================================================
|
|
101
|
+
# Tool - Diff
|
|
102
|
+
# =============================================================================
|
|
103
|
+
|
|
104
|
+
DIFF_MAX_LINE_LENGTH_FOR_CHAR_DIFF = 2000 # Maximum line length for character-level diff
|
|
105
|
+
DIFF_DEFAULT_CONTEXT_LINES = 3 # Default number of context lines in diff output
|
|
89
106
|
|
|
90
107
|
|
|
91
108
|
# =============================================================================
|
|
92
|
-
#
|
|
109
|
+
# Tool - Output Truncation
|
|
93
110
|
# =============================================================================
|
|
94
111
|
|
|
95
|
-
#
|
|
96
|
-
|
|
112
|
+
TOOL_OUTPUT_MAX_LENGTH = 40000 # Maximum length for tool output before truncation
|
|
113
|
+
TOOL_OUTPUT_DISPLAY_HEAD = 10000 # Characters to show from the beginning of truncated output
|
|
114
|
+
TOOL_OUTPUT_DISPLAY_TAIL = 10000 # Characters to show from the end of truncated output
|
|
115
|
+
TOOL_OUTPUT_TRUNCATION_DIR = "/tmp/klaude" # Directory for saving full truncated output
|
|
97
116
|
|
|
98
|
-
# Maximum lines to show in diff output
|
|
99
|
-
MAX_DIFF_LINES = 1000
|
|
100
117
|
|
|
101
|
-
#
|
|
102
|
-
|
|
118
|
+
# =============================================================================
|
|
119
|
+
# UI - Display
|
|
120
|
+
# =============================================================================
|
|
103
121
|
|
|
104
|
-
#
|
|
105
|
-
|
|
122
|
+
TAB_EXPAND_WIDTH = 8 # Tab expansion width for text rendering
|
|
123
|
+
DIFF_PREFIX_WIDTH = 4 # Width of line number prefix in diff display
|
|
124
|
+
MAX_DIFF_LINES = 500 # Maximum lines to show in diff output
|
|
125
|
+
INVALID_TOOL_CALL_MAX_LENGTH = 200 # Maximum length for invalid tool call display
|
|
126
|
+
TRUNCATE_DISPLAY_MAX_LINE_LENGTH = 200 # Maximum line length for truncated display
|
|
127
|
+
TRUNCATE_DISPLAY_MAX_LINES = 4 # Maximum lines for truncated display
|
|
128
|
+
MIN_HIDDEN_LINES_FOR_INDICATOR = 5 # Minimum hidden lines before showing truncation indicator
|
|
129
|
+
SUB_AGENT_RESULT_MAX_LINES = 10 # Maximum lines for sub-agent result display
|
|
130
|
+
TRUNCATE_HEAD_MAX_LINES = 2 # Maximum lines for sub-agent error display
|
|
131
|
+
BASH_OUTPUT_PANEL_THRESHOLD = 10 # Bash output line threshold for CodePanel display
|
|
132
|
+
BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES = 2 # Max lines shown for heredoc / multiline string tokens in bash tool calls
|
|
133
|
+
URL_TRUNCATE_MAX_LENGTH = 400 # Maximum length for URL truncation in display
|
|
134
|
+
QUERY_DISPLAY_TRUNCATE_LENGTH = 80 # Maximum length for search query display
|
|
135
|
+
NOTIFY_COMPACT_LIMIT = 160 # Maximum length for notification body text
|
|
106
136
|
|
|
107
|
-
# Maximum lines for truncated display output
|
|
108
|
-
TRUNCATE_DISPLAY_MAX_LINES = 8
|
|
109
137
|
|
|
110
|
-
#
|
|
111
|
-
|
|
138
|
+
# =============================================================================
|
|
139
|
+
# UI - Markdown Streaming
|
|
140
|
+
# =============================================================================
|
|
112
141
|
|
|
142
|
+
UI_REFRESH_RATE_FPS = 10 # UI refresh rate (frames per second)
|
|
143
|
+
CROP_ABOVE_LIVE_REFRESH_PER_SECOND = 4.0 # CropAboveLive default refresh rate
|
|
144
|
+
MARKDOWN_STREAM_LIVE_REPAINT_ENABLED = True # Enable live area for streaming markdown
|
|
145
|
+
STREAM_MAX_HEIGHT_SHRINK_RESET_LINES = 20 # Reset stream height ceiling after this shrinkage
|
|
146
|
+
MARKDOWN_LEFT_MARGIN = 2 # Left margin (columns) for markdown rendering
|
|
147
|
+
MARKDOWN_RIGHT_MARGIN = 2 # Right margin (columns) for markdown rendering
|
|
113
148
|
|
|
114
|
-
# UI refresh rate (frames per second) for debounced content streaming
|
|
115
|
-
UI_REFRESH_RATE_FPS = 10
|
|
116
149
|
|
|
117
|
-
#
|
|
118
|
-
#
|
|
119
|
-
|
|
150
|
+
# =============================================================================
|
|
151
|
+
# UI - Spinner / Status
|
|
152
|
+
# =============================================================================
|
|
120
153
|
|
|
121
|
-
|
|
122
|
-
|
|
154
|
+
STATUS_HINT_TEXT = " (esc to interrupt)" # Status hint text shown after spinner
|
|
155
|
+
STATUS_DEFAULT_TEXT = "Thinking …" # Default spinner status text
|
|
156
|
+
SPINNER_BREATH_PERIOD_SECONDS: float = 2.0 # Spinner breathing animation period (seconds)
|
|
157
|
+
STATUS_SHIMMER_PADDING = 10 # Horizontal padding for shimmer band position
|
|
158
|
+
STATUS_SHIMMER_BAND_HALF_WIDTH = 5.0 # Half-width of shimmer band in characters
|
|
159
|
+
STATUS_SHIMMER_ALPHA_SCALE = 0.7 # Scale factor for shimmer intensity
|
|
123
160
|
|
|
124
|
-
# Left margin (columns) to reserve when rendering markdown
|
|
125
|
-
MARKDOWN_LEFT_MARGIN = 2
|
|
126
161
|
|
|
127
|
-
#
|
|
128
|
-
|
|
162
|
+
# =============================================================================
|
|
163
|
+
# UI - Completion System
|
|
164
|
+
# =============================================================================
|
|
129
165
|
|
|
130
|
-
#
|
|
131
|
-
|
|
166
|
+
COMPLETER_DEBOUNCE_SEC = 0.25 # Debounce time for file path completion (seconds)
|
|
167
|
+
COMPLETER_CACHE_TTL_SEC = 60.0 # Cache TTL for completion results (seconds)
|
|
168
|
+
COMPLETER_CMD_TIMEOUT_SEC = 3.0 # Timeout for completion subprocess commands (seconds)
|
|
132
169
|
|
|
133
|
-
# Default spinner status text when idle/thinking
|
|
134
|
-
STATUS_DEFAULT_TEXT = "Thinking …"
|
|
135
170
|
|
|
136
|
-
#
|
|
137
|
-
#
|
|
138
|
-
|
|
139
|
-
# Half-width of the shimmer band in characters
|
|
140
|
-
STATUS_SHIMMER_BAND_HALF_WIDTH = 5.0
|
|
141
|
-
# Scale factor applied to shimmer intensity when blending colors
|
|
142
|
-
STATUS_SHIMMER_ALPHA_SCALE = 0.7
|
|
171
|
+
# =============================================================================
|
|
172
|
+
# Debug / Logging
|
|
173
|
+
# =============================================================================
|
|
143
174
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
175
|
+
DEFAULT_DEBUG_LOG_DIR = Path.home() / ".klaude" / "logs" # Default debug log directory
|
|
176
|
+
DEFAULT_DEBUG_LOG_FILE = DEFAULT_DEBUG_LOG_DIR / "debug.log" # Default debug log file path
|
|
177
|
+
LOG_MAX_BYTES = 10 * 1024 * 1024 # Maximum log file size before rotation (10MB)
|
|
178
|
+
LOG_BACKUP_COUNT = 3 # Number of backup log files to keep
|
|
148
179
|
|
|
149
180
|
|
|
150
181
|
# =============================================================================
|
|
151
|
-
#
|
|
182
|
+
# Project Paths
|
|
152
183
|
# =============================================================================
|
|
153
184
|
|
|
154
|
-
# Default debug log directory (user cache)
|
|
155
|
-
DEFAULT_DEBUG_LOG_DIR = Path.home() / ".klaude" / "logs"
|
|
156
185
|
|
|
157
|
-
|
|
158
|
-
|
|
186
|
+
def project_key_from_cwd() -> str:
|
|
187
|
+
"""Derive the project key from the current working directory."""
|
|
188
|
+
return str(Path.cwd()).strip("/").replace("/", "-")
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@dataclass(frozen=True)
|
|
192
|
+
class ProjectPaths:
|
|
193
|
+
"""Path utilities for project-scoped storage."""
|
|
194
|
+
|
|
195
|
+
project_key: str
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def base_dir(self) -> Path:
|
|
199
|
+
return Path.home() / ".klaude" / "projects" / self.project_key
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def sessions_dir(self) -> Path:
|
|
203
|
+
return self.base_dir / "sessions"
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def exports_dir(self) -> Path:
|
|
207
|
+
return self.base_dir / "exports"
|
|
208
|
+
|
|
209
|
+
def session_dir(self, session_id: str) -> Path:
|
|
210
|
+
return self.sessions_dir / session_id
|
|
211
|
+
|
|
212
|
+
def images_dir(self, session_id: str) -> Path:
|
|
213
|
+
"""Return the directory for storing session-scoped image artifacts."""
|
|
214
|
+
return self.session_dir(session_id) / "images"
|
|
159
215
|
|
|
160
|
-
|
|
161
|
-
|
|
216
|
+
def events_file(self, session_id: str) -> Path:
|
|
217
|
+
return self.session_dir(session_id) / "events.jsonl"
|
|
162
218
|
|
|
163
|
-
|
|
164
|
-
|
|
219
|
+
def meta_file(self, session_id: str) -> Path:
|
|
220
|
+
return self.session_dir(session_id) / "meta.json"
|
klaude_code/core/agent.py
CHANGED
|
@@ -9,8 +9,8 @@ from klaude_code.core.reminders import Reminder, load_agent_reminders
|
|
|
9
9
|
from klaude_code.core.task import SessionContext, TaskExecutionContext, TaskExecutor
|
|
10
10
|
from klaude_code.core.tool import build_todo_context, get_registry, load_agent_tools
|
|
11
11
|
from klaude_code.llm import LLMClientABC
|
|
12
|
-
from klaude_code.protocol import events, llm_param,
|
|
13
|
-
from klaude_code.protocol.
|
|
12
|
+
from klaude_code.protocol import events, llm_param, tools
|
|
13
|
+
from klaude_code.protocol.message import UserInputPayload
|
|
14
14
|
from klaude_code.session import Session
|
|
15
15
|
from klaude_code.trace import DebugType, log_debug
|
|
16
16
|
|
|
@@ -82,21 +82,12 @@ class Agent:
|
|
|
82
82
|
self.session.model_name = profile.llm_client.model_name
|
|
83
83
|
|
|
84
84
|
def cancel(self) -> Iterable[events.Event]:
|
|
85
|
-
"""Handle agent cancellation and
|
|
86
|
-
|
|
87
|
-
- Appends an `InterruptItem` into the session history so interruptions are reflected
|
|
88
|
-
in persisted conversation logs.
|
|
89
|
-
- For any tool calls that are pending or in-progress in the current task, delegate to
|
|
90
|
-
the active TaskExecutor to append synthetic ToolResultItem entries with error status
|
|
91
|
-
to indicate cancellation.
|
|
92
|
-
"""
|
|
85
|
+
"""Handle agent cancellation and tool cancellations."""
|
|
93
86
|
# First, cancel any running task so it stops emitting events.
|
|
94
87
|
if self._current_task is not None:
|
|
95
88
|
yield from self._current_task.cancel()
|
|
96
89
|
self._current_task = None
|
|
97
90
|
|
|
98
|
-
# Record an interrupt marker in the session history
|
|
99
|
-
self.session.append_history([model.InterruptItem()])
|
|
100
91
|
log_debug(
|
|
101
92
|
f"Session {self.session.id} interrupted",
|
|
102
93
|
style="yellow",
|