klaude-code 1.8.0__py3-none-any.whl → 2.0.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.
- klaude_code/auth/base.py +97 -0
- klaude_code/auth/claude/__init__.py +6 -0
- klaude_code/auth/claude/exceptions.py +9 -0
- klaude_code/auth/claude/oauth.py +172 -0
- klaude_code/auth/claude/token_manager.py +26 -0
- klaude_code/auth/codex/token_manager.py +10 -50
- klaude_code/cli/auth_cmd.py +127 -46
- klaude_code/cli/config_cmd.py +4 -2
- klaude_code/cli/cost_cmd.py +14 -9
- klaude_code/cli/list_model.py +248 -200
- 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 +82 -0
- 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 +52 -3
- klaude_code/config/builtin_config.py +16 -5
- klaude_code/config/config.py +31 -7
- klaude_code/config/thinking.py +4 -4
- klaude_code/const.py +146 -91
- klaude_code/core/agent.py +3 -12
- klaude_code/core/executor.py +21 -13
- klaude_code/core/manager/sub_agent_manager.py +71 -7
- klaude_code/core/prompt.py +1 -1
- 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 +8 -8
- 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 +104 -44
- klaude_code/llm/anthropic/input.py +116 -108
- klaude_code/llm/bedrock/client.py +8 -5
- klaude_code/llm/claude/__init__.py +3 -0
- klaude_code/llm/claude/client.py +105 -0
- klaude_code/llm/client.py +4 -3
- klaude_code/llm/codex/client.py +16 -10
- 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 -15
- 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 +22 -3
- klaude_code/protocol/message.py +250 -0
- klaude_code/protocol/model.py +94 -281
- klaude_code/protocol/op.py +2 -2
- klaude_code/protocol/sub_agent/__init__.py +2 -2
- 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 +125 -53
- 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 +136 -127
- klaude_code/ui/modes/repl/input_prompt_toolkit.py +1 -1
- klaude_code/ui/modes/repl/key_bindings.py +1 -1
- klaude_code/ui/modes/repl/renderer.py +107 -15
- klaude_code/ui/renderers/assistant.py +2 -2
- klaude_code/ui/renderers/common.py +65 -7
- 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 +39 -31
- klaude_code/ui/renderers/sub_agent.py +57 -16
- klaude_code/ui/renderers/thinking.py +37 -2
- klaude_code/ui/renderers/tools.py +180 -165
- 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 +13 -6
- 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 +55 -0
- {klaude_code-1.8.0.dist-info → klaude_code-2.0.0.dist-info}/METADATA +28 -6
- klaude_code-2.0.0.dist-info/RECORD +229 -0
- klaude_code/command/prompt-jj-describe.md +0 -32
- klaude_code/core/prompts/prompt-sub-agent-oracle.md +0 -22
- klaude_code/protocol/sub_agent/oracle.py +0 -91
- klaude_code-1.8.0.dist-info/RECORD +0 -219
- {klaude_code-1.8.0.dist-info → klaude_code-2.0.0.dist-info}/WHEEL +0 -0
- {klaude_code-1.8.0.dist-info → klaude_code-2.0.0.dist-info}/entry_points.txt +0 -0
|
@@ -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}
|
|
@@ -259,7 +272,6 @@ provider_list:
|
|
|
259
272
|
base_url: https://api.deepseek.com/anthropic
|
|
260
273
|
model_list:
|
|
261
274
|
- model_name: deepseek
|
|
262
|
-
provider: deepseek
|
|
263
275
|
model_params:
|
|
264
276
|
model: deepseek-reasoner
|
|
265
277
|
context_limit: 128000
|
|
@@ -290,14 +302,51 @@ provider_list:
|
|
|
290
302
|
cache_read: 1.0
|
|
291
303
|
currency: CNY
|
|
292
304
|
|
|
305
|
+
- provider_name: claude-max
|
|
306
|
+
protocol: claude_oauth
|
|
307
|
+
model_list:
|
|
308
|
+
- model_name: sonnet@claude-max
|
|
309
|
+
model_params:
|
|
310
|
+
model: claude-sonnet-4-5-20250929
|
|
311
|
+
context_limit: 200000
|
|
312
|
+
cost:
|
|
313
|
+
input: 3.0
|
|
314
|
+
output: 15.0
|
|
315
|
+
cache_read: 0.3
|
|
316
|
+
cache_write: 3.75
|
|
317
|
+
- model_name: opus@claude-max
|
|
318
|
+
model_params:
|
|
319
|
+
model: claude-opus-4-5-20251101
|
|
320
|
+
context_limit: 200000
|
|
321
|
+
verbosity: high
|
|
322
|
+
thinking:
|
|
323
|
+
type: enabled
|
|
324
|
+
budget_tokens: 2048
|
|
325
|
+
cost:
|
|
326
|
+
input: 5.0
|
|
327
|
+
output: 25.0
|
|
328
|
+
cache_read: 0.5
|
|
329
|
+
cache_write: 6.25
|
|
330
|
+
- model_name: haiku@claude-max
|
|
331
|
+
model_params:
|
|
332
|
+
model: claude-haiku-4-5-20251001
|
|
333
|
+
context_limit: 200000
|
|
334
|
+
cost:
|
|
335
|
+
input: 1.0
|
|
336
|
+
output: 5.0
|
|
337
|
+
cache_read: 0.1
|
|
338
|
+
cache_write: 1.25
|
|
339
|
+
|
|
293
340
|
- provider_name: codex
|
|
294
|
-
protocol:
|
|
341
|
+
protocol: codex_oauth
|
|
295
342
|
model_list:
|
|
296
343
|
- model_name: gpt-5.2-codex
|
|
297
|
-
provider: codex
|
|
298
344
|
model_params:
|
|
299
345
|
model: gpt-5.2-codex
|
|
300
346
|
thinking:
|
|
301
347
|
reasoning_effort: medium
|
|
302
348
|
context_limit: 400000
|
|
303
349
|
max_tokens: 128000
|
|
350
|
+
|
|
351
|
+
sub_agent_models:
|
|
352
|
+
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
|
|
@@ -81,14 +85,23 @@ class ProviderConfig(llm_param.LLMConfigProviderParameter):
|
|
|
81
85
|
"""
|
|
82
86
|
from klaude_code.protocol.llm_param import LLMClientProtocol
|
|
83
87
|
|
|
84
|
-
if self.protocol == LLMClientProtocol.
|
|
88
|
+
if self.protocol == LLMClientProtocol.CODEX_OAUTH:
|
|
85
89
|
# Codex uses OAuth authentication, not API key
|
|
86
90
|
from klaude_code.auth.codex.token_manager import CodexTokenManager
|
|
87
91
|
|
|
88
92
|
token_manager = CodexTokenManager()
|
|
89
93
|
state = token_manager.get_state()
|
|
90
|
-
# Consider available if logged in
|
|
91
|
-
return state is None
|
|
94
|
+
# Consider available if logged in. Token refresh happens on-demand.
|
|
95
|
+
return state is None
|
|
96
|
+
|
|
97
|
+
if self.protocol == LLMClientProtocol.CLAUDE_OAUTH:
|
|
98
|
+
# Claude uses OAuth authentication, not API key
|
|
99
|
+
from klaude_code.auth.claude.token_manager import ClaudeTokenManager
|
|
100
|
+
|
|
101
|
+
token_manager = ClaudeTokenManager()
|
|
102
|
+
state = token_manager.get_state()
|
|
103
|
+
# Consider available if logged in. Token refresh happens on-demand.
|
|
104
|
+
return state is None
|
|
92
105
|
|
|
93
106
|
if self.protocol == LLMClientProtocol.BEDROCK:
|
|
94
107
|
# Bedrock uses AWS credentials, not API key. Region is always required.
|
|
@@ -182,7 +195,17 @@ class Config(BaseModel):
|
|
|
182
195
|
for provider in self.provider_list:
|
|
183
196
|
# Resolve ${ENV_VAR} syntax for api_key
|
|
184
197
|
api_key = provider.get_resolved_api_key()
|
|
185
|
-
|
|
198
|
+
|
|
199
|
+
# Some protocols do not use API keys for authentication.
|
|
200
|
+
if (
|
|
201
|
+
provider.protocol
|
|
202
|
+
not in {
|
|
203
|
+
llm_param.LLMClientProtocol.CODEX_OAUTH,
|
|
204
|
+
llm_param.LLMClientProtocol.CLAUDE_OAUTH,
|
|
205
|
+
llm_param.LLMClientProtocol.BEDROCK,
|
|
206
|
+
}
|
|
207
|
+
and not api_key
|
|
208
|
+
):
|
|
186
209
|
continue
|
|
187
210
|
for model in provider.model_list:
|
|
188
211
|
if model.model_name == model_name:
|
|
@@ -243,7 +266,7 @@ def get_example_config() -> UserConfig:
|
|
|
243
266
|
"""Generate example config for user reference (will be commented out)."""
|
|
244
267
|
return UserConfig(
|
|
245
268
|
main_model="opus",
|
|
246
|
-
sub_agent_models={"explore": "haiku", "
|
|
269
|
+
sub_agent_models={"explore": "haiku", "webagent": "sonnet", "task": "sonnet"},
|
|
247
270
|
provider_list=[
|
|
248
271
|
UserProviderConfig(
|
|
249
272
|
provider_name="my-provider",
|
|
@@ -275,7 +298,8 @@ def _get_builtin_config() -> Config:
|
|
|
275
298
|
# Re-validate to ensure compatibility with current ProviderConfig class
|
|
276
299
|
# (needed for tests that may monkeypatch the class)
|
|
277
300
|
providers = [ProviderConfig.model_validate(p.model_dump()) for p in get_builtin_provider_configs()]
|
|
278
|
-
|
|
301
|
+
sub_agent_models = get_builtin_sub_agent_models()
|
|
302
|
+
return Config(provider_list=providers, sub_agent_models=sub_agent_models)
|
|
279
303
|
|
|
280
304
|
|
|
281
305
|
def _merge_provider(builtin: ProviderConfig, user: UserProviderConfig) -> ProviderConfig:
|
klaude_code/config/thinking.py
CHANGED
|
@@ -91,12 +91,12 @@ def format_current_thinking(config: llm_param.LLMConfigParameter) -> str:
|
|
|
91
91
|
|
|
92
92
|
protocol = config.protocol
|
|
93
93
|
|
|
94
|
-
if protocol in (llm_param.LLMClientProtocol.RESPONSES, llm_param.LLMClientProtocol.
|
|
94
|
+
if protocol in (llm_param.LLMClientProtocol.RESPONSES, llm_param.LLMClientProtocol.CODEX_OAUTH):
|
|
95
95
|
if thinking.reasoning_effort:
|
|
96
96
|
return f"reasoning_effort={thinking.reasoning_effort}"
|
|
97
97
|
return "not set"
|
|
98
98
|
|
|
99
|
-
if protocol
|
|
99
|
+
if protocol in (llm_param.LLMClientProtocol.ANTHROPIC, llm_param.LLMClientProtocol.CLAUDE_OAUTH):
|
|
100
100
|
if thinking.type == "disabled":
|
|
101
101
|
return "off"
|
|
102
102
|
if thinking.type == "enabled":
|
|
@@ -201,7 +201,7 @@ def get_thinking_picker_data(config: llm_param.LLMConfigParameter) -> ThinkingPi
|
|
|
201
201
|
model_name = config.model
|
|
202
202
|
thinking = config.thinking
|
|
203
203
|
|
|
204
|
-
if protocol in (llm_param.LLMClientProtocol.RESPONSES, llm_param.LLMClientProtocol.
|
|
204
|
+
if protocol in (llm_param.LLMClientProtocol.RESPONSES, llm_param.LLMClientProtocol.CODEX_OAUTH):
|
|
205
205
|
levels = get_levels_for_responses(model_name)
|
|
206
206
|
return ThinkingPickerData(
|
|
207
207
|
options=_build_effort_options(levels),
|
|
@@ -209,7 +209,7 @@ def get_thinking_picker_data(config: llm_param.LLMConfigParameter) -> ThinkingPi
|
|
|
209
209
|
current_value=_get_current_effort_value(thinking),
|
|
210
210
|
)
|
|
211
211
|
|
|
212
|
-
if protocol
|
|
212
|
+
if protocol in (llm_param.LLMClientProtocol.ANTHROPIC, llm_param.LLMClientProtocol.CLAUDE_OAUTH):
|
|
213
213
|
return ThinkingPickerData(
|
|
214
214
|
options=_build_budget_options(),
|
|
215
215
|
message="Select thinking level:",
|
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,197 @@ 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 = 500 # Maximum length for invalid tool call display
|
|
126
|
+
TRUNCATE_DISPLAY_MAX_LINE_LENGTH = 1000 # Maximum line length for truncated display
|
|
127
|
+
TRUNCATE_DISPLAY_MAX_LINES = 6 # 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
|
+
URL_TRUNCATE_MAX_LENGTH = 400 # Maximum length for URL truncation in display
|
|
133
|
+
QUERY_DISPLAY_TRUNCATE_LENGTH = 80 # Maximum length for search query display
|
|
134
|
+
NOTIFY_COMPACT_LIMIT = 160 # Maximum length for notification body text
|
|
106
135
|
|
|
107
|
-
# Maximum lines for truncated display output
|
|
108
|
-
TRUNCATE_DISPLAY_MAX_LINES = 8
|
|
109
136
|
|
|
110
|
-
#
|
|
111
|
-
|
|
137
|
+
# =============================================================================
|
|
138
|
+
# UI - Markdown Streaming
|
|
139
|
+
# =============================================================================
|
|
112
140
|
|
|
141
|
+
UI_REFRESH_RATE_FPS = 10 # UI refresh rate (frames per second)
|
|
142
|
+
CROP_ABOVE_LIVE_REFRESH_PER_SECOND = 4.0 # CropAboveLive default refresh rate
|
|
143
|
+
MARKDOWN_STREAM_LIVE_REPAINT_ENABLED = True # Enable live area for streaming markdown
|
|
144
|
+
STREAM_MAX_HEIGHT_SHRINK_RESET_LINES = 20 # Reset stream height ceiling after this shrinkage
|
|
145
|
+
MARKDOWN_LEFT_MARGIN = 2 # Left margin (columns) for markdown rendering
|
|
146
|
+
MARKDOWN_RIGHT_MARGIN = 2 # Right margin (columns) for markdown rendering
|
|
113
147
|
|
|
114
|
-
# UI refresh rate (frames per second) for debounced content streaming
|
|
115
|
-
UI_REFRESH_RATE_FPS = 10
|
|
116
148
|
|
|
117
|
-
#
|
|
118
|
-
#
|
|
119
|
-
|
|
149
|
+
# =============================================================================
|
|
150
|
+
# UI - Spinner / Status
|
|
151
|
+
# =============================================================================
|
|
120
152
|
|
|
121
|
-
|
|
122
|
-
|
|
153
|
+
STATUS_HINT_TEXT = " (esc to interrupt)" # Status hint text shown after spinner
|
|
154
|
+
STATUS_DEFAULT_TEXT = "Thinking …" # Default spinner status text
|
|
155
|
+
SPINNER_BREATH_PERIOD_SECONDS: float = 2.0 # Spinner breathing animation period (seconds)
|
|
156
|
+
STATUS_SHIMMER_PADDING = 10 # Horizontal padding for shimmer band position
|
|
157
|
+
STATUS_SHIMMER_BAND_HALF_WIDTH = 5.0 # Half-width of shimmer band in characters
|
|
158
|
+
STATUS_SHIMMER_ALPHA_SCALE = 0.7 # Scale factor for shimmer intensity
|
|
123
159
|
|
|
124
|
-
# Left margin (columns) to reserve when rendering markdown
|
|
125
|
-
MARKDOWN_LEFT_MARGIN = 2
|
|
126
160
|
|
|
127
|
-
#
|
|
128
|
-
|
|
161
|
+
# =============================================================================
|
|
162
|
+
# UI - Completion System
|
|
163
|
+
# =============================================================================
|
|
129
164
|
|
|
130
|
-
#
|
|
131
|
-
|
|
165
|
+
COMPLETER_DEBOUNCE_SEC = 0.25 # Debounce time for file path completion (seconds)
|
|
166
|
+
COMPLETER_CACHE_TTL_SEC = 60.0 # Cache TTL for completion results (seconds)
|
|
167
|
+
COMPLETER_CMD_TIMEOUT_SEC = 3.0 # Timeout for completion subprocess commands (seconds)
|
|
132
168
|
|
|
133
|
-
# Default spinner status text when idle/thinking
|
|
134
|
-
STATUS_DEFAULT_TEXT = "Thinking …"
|
|
135
169
|
|
|
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
|
|
170
|
+
# =============================================================================
|
|
171
|
+
# Debug / Logging
|
|
172
|
+
# =============================================================================
|
|
143
173
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
174
|
+
DEFAULT_DEBUG_LOG_DIR = Path.home() / ".klaude" / "logs" # Default debug log directory
|
|
175
|
+
DEFAULT_DEBUG_LOG_FILE = DEFAULT_DEBUG_LOG_DIR / "debug.log" # Default debug log file path
|
|
176
|
+
LOG_MAX_BYTES = 10 * 1024 * 1024 # Maximum log file size before rotation (10MB)
|
|
177
|
+
LOG_BACKUP_COUNT = 3 # Number of backup log files to keep
|
|
148
178
|
|
|
149
179
|
|
|
150
180
|
# =============================================================================
|
|
151
|
-
#
|
|
181
|
+
# Project Paths
|
|
152
182
|
# =============================================================================
|
|
153
183
|
|
|
154
|
-
# Default debug log directory (user cache)
|
|
155
|
-
DEFAULT_DEBUG_LOG_DIR = Path.home() / ".klaude" / "logs"
|
|
156
184
|
|
|
157
|
-
|
|
158
|
-
|
|
185
|
+
def project_key_from_cwd() -> str:
|
|
186
|
+
"""Derive the project key from the current working directory."""
|
|
187
|
+
return str(Path.cwd()).strip("/").replace("/", "-")
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@dataclass(frozen=True)
|
|
191
|
+
class ProjectPaths:
|
|
192
|
+
"""Path utilities for project-scoped storage."""
|
|
193
|
+
|
|
194
|
+
project_key: str
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def base_dir(self) -> Path:
|
|
198
|
+
return Path.home() / ".klaude" / "projects" / self.project_key
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def sessions_dir(self) -> Path:
|
|
202
|
+
return self.base_dir / "sessions"
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def exports_dir(self) -> Path:
|
|
206
|
+
return self.base_dir / "exports"
|
|
207
|
+
|
|
208
|
+
def session_dir(self, session_id: str) -> Path:
|
|
209
|
+
return self.sessions_dir / session_id
|
|
210
|
+
|
|
211
|
+
def images_dir(self, session_id: str) -> Path:
|
|
212
|
+
"""Return the directory for storing session-scoped image artifacts."""
|
|
213
|
+
return self.session_dir(session_id) / "images"
|
|
159
214
|
|
|
160
|
-
|
|
161
|
-
|
|
215
|
+
def events_file(self, session_id: str) -> Path:
|
|
216
|
+
return self.session_dir(session_id) / "events.jsonl"
|
|
162
217
|
|
|
163
|
-
|
|
164
|
-
|
|
218
|
+
def meta_file(self, session_id: str) -> Path:
|
|
219
|
+
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",
|