klaude-code 2.0.1__py3-none-any.whl → 2.1.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/app/__init__.py +12 -0
- klaude_code/app/runtime.py +215 -0
- klaude_code/cli/auth_cmd.py +2 -2
- klaude_code/cli/config_cmd.py +2 -2
- klaude_code/cli/cost_cmd.py +1 -1
- klaude_code/cli/debug.py +12 -36
- klaude_code/cli/list_model.py +3 -3
- klaude_code/cli/main.py +17 -60
- klaude_code/cli/self_update.py +2 -187
- klaude_code/cli/session_cmd.py +2 -2
- klaude_code/config/config.py +1 -1
- klaude_code/config/select_model.py +1 -1
- klaude_code/const.py +10 -1
- klaude_code/core/agent.py +9 -62
- klaude_code/core/agent_profile.py +284 -0
- klaude_code/core/executor.py +343 -230
- klaude_code/core/manager/llm_clients_builder.py +1 -1
- klaude_code/core/manager/sub_agent_manager.py +16 -29
- klaude_code/core/reminders.py +107 -155
- klaude_code/core/task.py +12 -20
- klaude_code/core/tool/__init__.py +5 -19
- klaude_code/core/tool/context.py +84 -0
- klaude_code/core/tool/file/apply_patch_tool.py +18 -21
- klaude_code/core/tool/file/edit_tool.py +42 -44
- klaude_code/core/tool/file/read_tool.py +14 -9
- klaude_code/core/tool/file/write_tool.py +12 -13
- klaude_code/core/tool/report_back_tool.py +4 -1
- klaude_code/core/tool/shell/bash_tool.py +6 -11
- klaude_code/core/tool/skill/skill_tool.py +3 -1
- klaude_code/core/tool/sub_agent_tool.py +8 -7
- klaude_code/core/tool/todo/todo_write_tool.py +3 -9
- klaude_code/core/tool/todo/update_plan_tool.py +3 -5
- klaude_code/core/tool/tool_abc.py +2 -1
- klaude_code/core/tool/tool_registry.py +2 -33
- klaude_code/core/tool/tool_runner.py +13 -10
- klaude_code/core/tool/web/mermaid_tool.py +3 -1
- klaude_code/core/tool/web/web_fetch_tool.py +5 -3
- klaude_code/core/tool/web/web_search_tool.py +5 -3
- klaude_code/core/turn.py +86 -26
- klaude_code/llm/anthropic/client.py +1 -1
- klaude_code/llm/bedrock/client.py +1 -1
- klaude_code/llm/claude/client.py +1 -1
- klaude_code/llm/codex/client.py +1 -1
- klaude_code/llm/google/client.py +1 -1
- klaude_code/llm/openai_compatible/client.py +1 -1
- klaude_code/llm/openai_compatible/tool_call_accumulator.py +1 -1
- klaude_code/llm/openrouter/client.py +1 -1
- klaude_code/llm/openrouter/reasoning.py +1 -1
- klaude_code/llm/responses/client.py +1 -1
- klaude_code/protocol/events/__init__.py +57 -0
- klaude_code/protocol/events/base.py +18 -0
- klaude_code/protocol/events/chat.py +20 -0
- klaude_code/protocol/events/lifecycle.py +22 -0
- klaude_code/protocol/events/metadata.py +15 -0
- klaude_code/protocol/events/streaming.py +43 -0
- klaude_code/protocol/events/system.py +53 -0
- klaude_code/protocol/events/tools.py +23 -0
- klaude_code/protocol/message.py +3 -11
- klaude_code/protocol/model.py +78 -9
- klaude_code/protocol/op.py +5 -0
- klaude_code/protocol/sub_agent/explore.py +0 -15
- klaude_code/protocol/sub_agent/task.py +1 -1
- klaude_code/protocol/sub_agent/web.py +1 -17
- klaude_code/protocol/tools.py +0 -1
- klaude_code/session/session.py +6 -5
- klaude_code/skill/assets/create-plan/SKILL.md +76 -0
- klaude_code/skill/loader.py +1 -1
- klaude_code/skill/system_skills.py +1 -1
- klaude_code/tui/__init__.py +8 -0
- klaude_code/{command → tui/command}/clear_cmd.py +2 -1
- klaude_code/{command → tui/command}/debug_cmd.py +4 -3
- klaude_code/{command → tui/command}/export_cmd.py +2 -1
- klaude_code/{command → tui/command}/export_online_cmd.py +6 -5
- klaude_code/{command → tui/command}/fork_session_cmd.py +10 -9
- klaude_code/{command → tui/command}/help_cmd.py +3 -2
- klaude_code/{command → tui/command}/model_cmd.py +5 -4
- klaude_code/{command → tui/command}/model_select.py +2 -2
- klaude_code/{command → tui/command}/prompt_command.py +4 -3
- klaude_code/{command → tui/command}/refresh_cmd.py +3 -1
- klaude_code/{command → tui/command}/registry.py +16 -6
- klaude_code/{command → tui/command}/release_notes_cmd.py +3 -2
- klaude_code/{command → tui/command}/resume_cmd.py +6 -5
- klaude_code/{command → tui/command}/status_cmd.py +4 -3
- klaude_code/{command → tui/command}/terminal_setup_cmd.py +4 -3
- klaude_code/{command → tui/command}/thinking_cmd.py +4 -3
- klaude_code/tui/commands.py +164 -0
- klaude_code/{ui/renderers → tui/components}/assistant.py +3 -3
- klaude_code/{ui/renderers → tui/components}/bash_syntax.py +2 -2
- klaude_code/{ui/renderers → tui/components}/common.py +1 -1
- klaude_code/tui/components/developer.py +231 -0
- klaude_code/{ui/renderers → tui/components}/diffs.py +2 -2
- klaude_code/{ui/renderers → tui/components}/errors.py +2 -2
- klaude_code/{ui/renderers → tui/components}/metadata.py +34 -21
- klaude_code/{ui → tui/components}/rich/markdown.py +78 -34
- klaude_code/{ui → tui/components}/rich/status.py +2 -2
- klaude_code/{ui → tui/components}/rich/theme.py +12 -5
- klaude_code/{ui/renderers → tui/components}/sub_agent.py +23 -43
- klaude_code/{ui/renderers → tui/components}/thinking.py +3 -3
- klaude_code/{ui/renderers → tui/components}/tools.py +11 -48
- klaude_code/{ui/renderers → tui/components}/user_input.py +3 -20
- klaude_code/tui/display.py +85 -0
- klaude_code/{ui/modes/repl → tui/input}/__init__.py +1 -1
- klaude_code/{ui/modes/repl → tui/input}/completers.py +1 -1
- klaude_code/{ui/modes/repl/input_prompt_toolkit.py → tui/input/prompt_toolkit.py} +11 -7
- klaude_code/tui/machine.py +606 -0
- klaude_code/tui/renderer.py +707 -0
- klaude_code/tui/runner.py +321 -0
- klaude_code/tui/terminal/__init__.py +56 -0
- klaude_code/{ui → tui}/terminal/color.py +1 -1
- klaude_code/{ui → tui}/terminal/control.py +1 -1
- klaude_code/{ui → tui}/terminal/notifier.py +1 -1
- klaude_code/{ui → tui}/terminal/selector.py +36 -17
- klaude_code/ui/__init__.py +6 -50
- klaude_code/ui/core/display.py +3 -3
- klaude_code/ui/core/input.py +2 -1
- klaude_code/ui/{modes/debug/display.py → debug_mode.py} +1 -1
- klaude_code/ui/{modes/exec/display.py → exec_mode.py} +1 -4
- klaude_code/ui/terminal/__init__.py +6 -54
- klaude_code/ui/terminal/title.py +31 -0
- klaude_code/update.py +163 -0
- {klaude_code-2.0.1.dist-info → klaude_code-2.1.0.dist-info}/METADATA +1 -1
- klaude_code-2.1.0.dist-info/RECORD +235 -0
- klaude_code/cli/runtime.py +0 -525
- klaude_code/core/prompt.py +0 -108
- klaude_code/core/tool/file/move_tool.md +0 -41
- klaude_code/core/tool/file/move_tool.py +0 -435
- klaude_code/core/tool/tool_context.py +0 -148
- klaude_code/protocol/events.py +0 -194
- klaude_code/skill/assets/dev-docs/SKILL.md +0 -108
- klaude_code/trace/__init__.py +0 -21
- klaude_code/ui/core/stage_manager.py +0 -48
- klaude_code/ui/modes/__init__.py +0 -1
- klaude_code/ui/modes/debug/__init__.py +0 -1
- klaude_code/ui/modes/exec/__init__.py +0 -1
- klaude_code/ui/modes/repl/display.py +0 -61
- klaude_code/ui/modes/repl/event_handler.py +0 -634
- klaude_code/ui/modes/repl/renderer.py +0 -463
- klaude_code/ui/renderers/developer.py +0 -215
- klaude_code/ui/utils/__init__.py +0 -1
- klaude_code-2.0.1.dist-info/RECORD +0 -229
- /klaude_code/{trace/log.py → log.py} +0 -0
- /klaude_code/{command → tui/command}/__init__.py +0 -0
- /klaude_code/{command → tui/command}/command_abc.py +0 -0
- /klaude_code/{command → tui/command}/prompt-commit.md +0 -0
- /klaude_code/{command → tui/command}/prompt-init.md +0 -0
- /klaude_code/{ui/renderers → tui/components}/__init__.py +0 -0
- /klaude_code/{ui/renderers → tui/components}/mermaid_viewer.py +0 -0
- /klaude_code/{ui → tui/components}/rich/__init__.py +0 -0
- /klaude_code/{ui → tui/components}/rich/cjk_wrap.py +0 -0
- /klaude_code/{ui → tui/components}/rich/code_panel.py +0 -0
- /klaude_code/{ui → tui/components}/rich/live.py +0 -0
- /klaude_code/{ui → tui/components}/rich/quote.py +0 -0
- /klaude_code/{ui → tui/components}/rich/searchable_text.py +0 -0
- /klaude_code/{ui/modes/repl → tui/input}/clipboard.py +0 -0
- /klaude_code/{ui/modes/repl → tui/input}/key_bindings.py +0 -0
- /klaude_code/{ui → tui}/terminal/image.py +0 -0
- /klaude_code/{ui → tui}/terminal/progress_bar.py +0 -0
- /klaude_code/ui/{utils/common.py → common.py} +0 -0
- {klaude_code-2.0.1.dist-info → klaude_code-2.1.0.dist-info}/WHEEL +0 -0
- {klaude_code-2.0.1.dist-info → klaude_code-2.1.0.dist-info}/entry_points.txt +0 -0
|
@@ -6,8 +6,8 @@ from pathlib import Path
|
|
|
6
6
|
|
|
7
7
|
from pydantic import BaseModel, field_validator
|
|
8
8
|
|
|
9
|
+
from klaude_code.core.tool.context import ToolContext
|
|
9
10
|
from klaude_code.core.tool.tool_abc import ToolABC, load_desc
|
|
10
|
-
from klaude_code.core.tool.tool_context import get_current_todo_context
|
|
11
11
|
from klaude_code.core.tool.tool_registry import register
|
|
12
12
|
from klaude_code.protocol import llm_param, message, model, tools
|
|
13
13
|
|
|
@@ -79,15 +79,13 @@ class UpdatePlanTool(ToolABC):
|
|
|
79
79
|
)
|
|
80
80
|
|
|
81
81
|
@classmethod
|
|
82
|
-
async def call(cls, arguments: str) -> message.ToolResultMessage:
|
|
82
|
+
async def call(cls, arguments: str, context: ToolContext) -> message.ToolResultMessage:
|
|
83
83
|
try:
|
|
84
84
|
args = UpdatePlanArguments.model_validate_json(arguments)
|
|
85
85
|
except ValueError as exc:
|
|
86
86
|
return message.ToolResultMessage(status="error", output_text=f"Invalid arguments: {exc}")
|
|
87
87
|
|
|
88
|
-
todo_context =
|
|
89
|
-
if todo_context is None:
|
|
90
|
-
return message.ToolResultMessage(status="error", output_text="No active session found")
|
|
88
|
+
todo_context = context.todo_context
|
|
91
89
|
|
|
92
90
|
new_todos = [model.TodoItem(content=item.step, status=item.status) for item in args.plan]
|
|
93
91
|
old_todos = todo_context.get_todos()
|
|
@@ -4,6 +4,7 @@ from dataclasses import dataclass
|
|
|
4
4
|
from enum import Enum
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
+
from klaude_code.core.tool.context import ToolContext
|
|
7
8
|
from klaude_code.protocol import llm_param, message
|
|
8
9
|
|
|
9
10
|
|
|
@@ -27,7 +28,7 @@ class ToolABC(ABC):
|
|
|
27
28
|
|
|
28
29
|
@classmethod
|
|
29
30
|
@abstractmethod
|
|
30
|
-
async def call(cls, arguments: str) -> message.ToolResultMessage:
|
|
31
|
+
async def call(cls, arguments: str, context: ToolContext) -> message.ToolResultMessage:
|
|
31
32
|
raise NotImplementedError
|
|
32
33
|
|
|
33
34
|
|
|
@@ -3,8 +3,8 @@ from typing import TypeVar
|
|
|
3
3
|
|
|
4
4
|
from klaude_code.core.tool.sub_agent_tool import SubAgentTool
|
|
5
5
|
from klaude_code.core.tool.tool_abc import ToolABC
|
|
6
|
-
from klaude_code.protocol import llm_param
|
|
7
|
-
from klaude_code.protocol.sub_agent import
|
|
6
|
+
from klaude_code.protocol import llm_param
|
|
7
|
+
from klaude_code.protocol.sub_agent import iter_sub_agent_profiles
|
|
8
8
|
|
|
9
9
|
_REGISTRY: dict[str, type[ToolABC]] = {}
|
|
10
10
|
|
|
@@ -45,34 +45,3 @@ def get_tool_schemas(tool_names: list[str]) -> list[llm_param.ToolSchema]:
|
|
|
45
45
|
def get_registry() -> dict[str, type[ToolABC]]:
|
|
46
46
|
"""Get the global tool registry."""
|
|
47
47
|
return _REGISTRY
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def load_agent_tools(
|
|
51
|
-
model_name: str, sub_agent_type: tools.SubAgentType | None = None, *, vanilla: bool = False
|
|
52
|
-
) -> list[llm_param.ToolSchema]:
|
|
53
|
-
"""Get tools for an agent based on model and agent type.
|
|
54
|
-
|
|
55
|
-
Args:
|
|
56
|
-
model_name: The model name.
|
|
57
|
-
sub_agent_type: If None, returns main agent tools. Otherwise returns sub-agent tools.
|
|
58
|
-
vanilla: If True, returns minimal vanilla tools (ignores sub_agent_type).
|
|
59
|
-
"""
|
|
60
|
-
if vanilla:
|
|
61
|
-
return get_tool_schemas([tools.BASH, tools.EDIT, tools.WRITE, tools.READ])
|
|
62
|
-
|
|
63
|
-
if sub_agent_type is not None:
|
|
64
|
-
profile = get_sub_agent_profile(sub_agent_type)
|
|
65
|
-
return get_tool_schemas(list(profile.tool_set))
|
|
66
|
-
|
|
67
|
-
# Main agent tools
|
|
68
|
-
if "gpt-5" in model_name:
|
|
69
|
-
tool_names = [tools.BASH, tools.READ, tools.APPLY_PATCH, tools.MOVE, tools.UPDATE_PLAN]
|
|
70
|
-
elif "gemini-3" in model_name:
|
|
71
|
-
tool_names = [tools.BASH, tools.READ, tools.EDIT, tools.WRITE, tools.MOVE]
|
|
72
|
-
else:
|
|
73
|
-
tool_names = [tools.BASH, tools.READ, tools.EDIT, tools.WRITE, tools.MOVE, tools.TODO_WRITE]
|
|
74
|
-
|
|
75
|
-
tool_names.extend(sub_agent_tool_names(enabled_only=True, model_name=model_name))
|
|
76
|
-
tool_names.extend([tools.SKILL, tools.MERMAID])
|
|
77
|
-
# tool_names.extend([tools.MEMORY])
|
|
78
|
-
return get_tool_schemas(tool_names)
|
|
@@ -3,9 +3,9 @@ from collections.abc import AsyncGenerator, Callable, Iterable, Sequence
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
|
|
5
5
|
from klaude_code.const import CANCEL_OUTPUT
|
|
6
|
+
from klaude_code.core.tool.context import ToolContext
|
|
6
7
|
from klaude_code.core.tool.report_back_tool import ReportBackTool
|
|
7
8
|
from klaude_code.core.tool.tool_abc import ToolABC, ToolConcurrencyPolicy
|
|
8
|
-
from klaude_code.core.tool.tool_context import current_sub_agent_session_id_recorder
|
|
9
9
|
from klaude_code.core.tool.truncation import truncate_tool_output
|
|
10
10
|
from klaude_code.protocol import message, model, tools
|
|
11
11
|
|
|
@@ -18,19 +18,24 @@ class ToolCallRequest:
|
|
|
18
18
|
arguments_json: str
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
async def run_tool(
|
|
21
|
+
async def run_tool(
|
|
22
|
+
tool_call: ToolCallRequest,
|
|
23
|
+
registry: dict[str, type[ToolABC]],
|
|
24
|
+
context: ToolContext,
|
|
25
|
+
) -> message.ToolResultMessage:
|
|
22
26
|
"""Execute a tool call and return the result.
|
|
23
27
|
|
|
24
28
|
Args:
|
|
25
29
|
tool_call: The tool call to execute.
|
|
26
30
|
registry: The tool registry mapping tool names to tool classes.
|
|
31
|
+
context: The explicit tool execution context.
|
|
27
32
|
|
|
28
33
|
Returns:
|
|
29
34
|
The result of the tool execution.
|
|
30
35
|
"""
|
|
31
36
|
# Special handling for report_back tool (not registered in global registry)
|
|
32
37
|
if tool_call.tool_name == tools.REPORT_BACK:
|
|
33
|
-
tool_result = await ReportBackTool.call(tool_call.arguments_json)
|
|
38
|
+
tool_result = await ReportBackTool.call(tool_call.arguments_json, context)
|
|
34
39
|
tool_result.call_id = tool_call.call_id
|
|
35
40
|
tool_result.tool_name = tool_call.tool_name
|
|
36
41
|
return tool_result
|
|
@@ -43,7 +48,7 @@ async def run_tool(tool_call: ToolCallRequest, registry: dict[str, type[ToolABC]
|
|
|
43
48
|
tool_name=tool_call.tool_name,
|
|
44
49
|
)
|
|
45
50
|
try:
|
|
46
|
-
tool_result = await registry[tool_call.tool_name].call(tool_call.arguments_json)
|
|
51
|
+
tool_result = await registry[tool_call.tool_name].call(tool_call.arguments_json, context)
|
|
47
52
|
tool_result.call_id = tool_call.call_id
|
|
48
53
|
tool_result.tool_name = tool_call.tool_name
|
|
49
54
|
if tool_result.output_text:
|
|
@@ -109,9 +114,11 @@ class ToolExecutor:
|
|
|
109
114
|
def __init__(
|
|
110
115
|
self,
|
|
111
116
|
*,
|
|
117
|
+
context: ToolContext,
|
|
112
118
|
registry: dict[str, type[ToolABC]],
|
|
113
119
|
append_history: Callable[[Sequence[message.HistoryEvent]], None],
|
|
114
120
|
) -> None:
|
|
121
|
+
self._context = context
|
|
115
122
|
self._registry = registry
|
|
116
123
|
self._append_history = append_history
|
|
117
124
|
|
|
@@ -268,15 +275,11 @@ class ToolExecutor:
|
|
|
268
275
|
|
|
269
276
|
async def _run_single_tool_call(self, tool_call: ToolCallRequest) -> list[ToolExecutorEvent]:
|
|
270
277
|
def _record_sub_agent_session_id(session_id: str) -> None:
|
|
271
|
-
# Keep the first recorded id if multiple writes happen.
|
|
272
278
|
if tool_call.call_id not in self._sub_agent_session_ids:
|
|
273
279
|
self._sub_agent_session_ids[tool_call.call_id] = session_id
|
|
274
280
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
tool_result: message.ToolResultMessage = await run_tool(tool_call, self._registry)
|
|
278
|
-
finally:
|
|
279
|
-
current_sub_agent_session_id_recorder.reset(recorder_token)
|
|
281
|
+
call_context = self._context.with_record_sub_agent_session_id(_record_sub_agent_session_id)
|
|
282
|
+
tool_result: message.ToolResultMessage = await run_tool(tool_call, self._registry, call_context)
|
|
280
283
|
|
|
281
284
|
self._append_history([tool_result])
|
|
282
285
|
|
|
@@ -8,6 +8,7 @@ from pathlib import Path
|
|
|
8
8
|
from pydantic import BaseModel, Field
|
|
9
9
|
|
|
10
10
|
from klaude_code.const import MERMAID_LIVE_PREFIX
|
|
11
|
+
from klaude_code.core.tool.context import ToolContext
|
|
11
12
|
from klaude_code.core.tool.tool_abc import ToolABC, load_desc
|
|
12
13
|
from klaude_code.core.tool.tool_registry import register
|
|
13
14
|
from klaude_code.protocol import llm_param, message, model, tools
|
|
@@ -40,7 +41,8 @@ class MermaidTool(ToolABC):
|
|
|
40
41
|
)
|
|
41
42
|
|
|
42
43
|
@classmethod
|
|
43
|
-
async def call(cls, arguments: str) -> message.ToolResultMessage:
|
|
44
|
+
async def call(cls, arguments: str, context: ToolContext) -> message.ToolResultMessage:
|
|
45
|
+
del context
|
|
44
46
|
try:
|
|
45
47
|
args = cls.MermaidArguments.model_validate_json(arguments)
|
|
46
48
|
except Exception as exc: # pragma: no cover - defensive
|
|
@@ -16,6 +16,7 @@ from klaude_code.const import (
|
|
|
16
16
|
WEB_FETCH_DEFAULT_TIMEOUT_SEC,
|
|
17
17
|
WEB_FETCH_USER_AGENT,
|
|
18
18
|
)
|
|
19
|
+
from klaude_code.core.tool.context import ToolContext
|
|
19
20
|
from klaude_code.core.tool.tool_abc import ToolABC, ToolConcurrencyPolicy, ToolMetadata, load_desc
|
|
20
21
|
from klaude_code.core.tool.tool_registry import register
|
|
21
22
|
from klaude_code.protocol import llm_param, message, tools
|
|
@@ -213,7 +214,7 @@ class WebFetchTool(ToolABC):
|
|
|
213
214
|
url: str
|
|
214
215
|
|
|
215
216
|
@classmethod
|
|
216
|
-
async def call(cls, arguments: str) -> message.ToolResultMessage:
|
|
217
|
+
async def call(cls, arguments: str, context: ToolContext) -> message.ToolResultMessage:
|
|
217
218
|
try:
|
|
218
219
|
args = WebFetchTool.WebFetchArguments.model_validate_json(arguments)
|
|
219
220
|
except ValueError as e:
|
|
@@ -221,10 +222,11 @@ class WebFetchTool(ToolABC):
|
|
|
221
222
|
status="error",
|
|
222
223
|
output_text=f"Invalid arguments: {e}",
|
|
223
224
|
)
|
|
224
|
-
return await cls.call_with_args(args)
|
|
225
|
+
return await cls.call_with_args(args, context)
|
|
225
226
|
|
|
226
227
|
@classmethod
|
|
227
|
-
async def call_with_args(cls, args: WebFetchArguments) -> message.ToolResultMessage:
|
|
228
|
+
async def call_with_args(cls, args: WebFetchArguments, context: ToolContext) -> message.ToolResultMessage:
|
|
229
|
+
del context
|
|
228
230
|
url = args.url
|
|
229
231
|
|
|
230
232
|
# Basic URL validation
|
|
@@ -5,6 +5,7 @@ from pathlib import Path
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
|
|
7
7
|
from klaude_code.const import WEB_SEARCH_DEFAULT_MAX_RESULTS, WEB_SEARCH_MAX_RESULTS_LIMIT
|
|
8
|
+
from klaude_code.core.tool.context import ToolContext
|
|
8
9
|
from klaude_code.core.tool.tool_abc import ToolABC, ToolConcurrencyPolicy, ToolMetadata, load_desc
|
|
9
10
|
from klaude_code.core.tool.tool_registry import register
|
|
10
11
|
from klaude_code.protocol import llm_param, message, tools
|
|
@@ -91,7 +92,7 @@ class WebSearchTool(ToolABC):
|
|
|
91
92
|
max_results: int = WEB_SEARCH_DEFAULT_MAX_RESULTS
|
|
92
93
|
|
|
93
94
|
@classmethod
|
|
94
|
-
async def call(cls, arguments: str) -> message.ToolResultMessage:
|
|
95
|
+
async def call(cls, arguments: str, context: ToolContext) -> message.ToolResultMessage:
|
|
95
96
|
try:
|
|
96
97
|
args = WebSearchTool.WebSearchArguments.model_validate_json(arguments)
|
|
97
98
|
except ValueError as e:
|
|
@@ -99,10 +100,11 @@ class WebSearchTool(ToolABC):
|
|
|
99
100
|
status="error",
|
|
100
101
|
output_text=f"Invalid arguments: {e}",
|
|
101
102
|
)
|
|
102
|
-
return await cls.call_with_args(args)
|
|
103
|
+
return await cls.call_with_args(args, context)
|
|
103
104
|
|
|
104
105
|
@classmethod
|
|
105
|
-
async def call_with_args(cls, args: WebSearchArguments) -> message.ToolResultMessage:
|
|
106
|
+
async def call_with_args(cls, args: WebSearchArguments, context: ToolContext) -> message.ToolResultMessage:
|
|
107
|
+
del context
|
|
106
108
|
query = args.query.strip()
|
|
107
109
|
if not query:
|
|
108
110
|
return message.ToolResultMessage(
|
klaude_code/core/turn.py
CHANGED
|
@@ -5,8 +5,8 @@ from dataclasses import dataclass, field
|
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
7
|
from klaude_code.const import INTERRUPT_MARKER, SUPPORTED_IMAGE_SIZES
|
|
8
|
-
from klaude_code.core.tool import ToolABC
|
|
9
|
-
from klaude_code.core.tool.
|
|
8
|
+
from klaude_code.core.tool import ToolABC
|
|
9
|
+
from klaude_code.core.tool.context import SubAgentResumeClaims, ToolContext
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
12
|
from klaude_code.core.task import SessionContext
|
|
@@ -20,8 +20,8 @@ from klaude_code.core.tool.tool_runner import (
|
|
|
20
20
|
ToolExecutorEvent,
|
|
21
21
|
)
|
|
22
22
|
from klaude_code.llm import LLMClientABC
|
|
23
|
+
from klaude_code.log import DebugType, log_debug
|
|
23
24
|
from klaude_code.protocol import events, llm_param, message, model, tools
|
|
24
|
-
from klaude_code.trace import DebugType, log_debug
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class TurnError(Exception):
|
|
@@ -206,6 +206,8 @@ class TurnExecutor:
|
|
|
206
206
|
|
|
207
207
|
ctx = self._context
|
|
208
208
|
session_ctx = ctx.session_ctx
|
|
209
|
+
thinking_active = False
|
|
210
|
+
assistant_text_active = False
|
|
209
211
|
message_types = (
|
|
210
212
|
message.SystemMessage,
|
|
211
213
|
message.DeveloperMessage,
|
|
@@ -247,12 +249,30 @@ class TurnExecutor:
|
|
|
247
249
|
)
|
|
248
250
|
match delta:
|
|
249
251
|
case message.ThinkingTextDelta() as delta:
|
|
252
|
+
if not thinking_active:
|
|
253
|
+
thinking_active = True
|
|
254
|
+
yield events.ThinkingStartEvent(
|
|
255
|
+
response_id=delta.response_id,
|
|
256
|
+
session_id=session_ctx.session_id,
|
|
257
|
+
)
|
|
250
258
|
yield events.ThinkingDeltaEvent(
|
|
251
259
|
content=delta.content,
|
|
252
260
|
response_id=delta.response_id,
|
|
253
261
|
session_id=session_ctx.session_id,
|
|
254
262
|
)
|
|
255
263
|
case message.AssistantTextDelta() as delta:
|
|
264
|
+
if thinking_active:
|
|
265
|
+
thinking_active = False
|
|
266
|
+
yield events.ThinkingEndEvent(
|
|
267
|
+
response_id=delta.response_id,
|
|
268
|
+
session_id=session_ctx.session_id,
|
|
269
|
+
)
|
|
270
|
+
if not assistant_text_active:
|
|
271
|
+
assistant_text_active = True
|
|
272
|
+
yield events.AssistantTextStartEvent(
|
|
273
|
+
response_id=delta.response_id,
|
|
274
|
+
session_id=session_ctx.session_id,
|
|
275
|
+
)
|
|
256
276
|
if delta.response_id:
|
|
257
277
|
self._assistant_response_id = delta.response_id
|
|
258
278
|
self._assistant_delta_buffer.append(delta.content)
|
|
@@ -262,6 +282,12 @@ class TurnExecutor:
|
|
|
262
282
|
session_id=session_ctx.session_id,
|
|
263
283
|
)
|
|
264
284
|
case message.AssistantImageDelta() as delta:
|
|
285
|
+
if thinking_active:
|
|
286
|
+
thinking_active = False
|
|
287
|
+
yield events.ThinkingEndEvent(
|
|
288
|
+
response_id=delta.response_id,
|
|
289
|
+
session_id=session_ctx.session_id,
|
|
290
|
+
)
|
|
265
291
|
yield events.AssistantImageDeltaEvent(
|
|
266
292
|
file_path=delta.file_path,
|
|
267
293
|
response_id=delta.response_id,
|
|
@@ -270,6 +296,18 @@ class TurnExecutor:
|
|
|
270
296
|
case message.AssistantMessage() as msg:
|
|
271
297
|
if msg.response_id is None and self._assistant_response_id:
|
|
272
298
|
msg.response_id = self._assistant_response_id
|
|
299
|
+
if thinking_active:
|
|
300
|
+
thinking_active = False
|
|
301
|
+
yield events.ThinkingEndEvent(
|
|
302
|
+
response_id=msg.response_id,
|
|
303
|
+
session_id=session_ctx.session_id,
|
|
304
|
+
)
|
|
305
|
+
if assistant_text_active:
|
|
306
|
+
assistant_text_active = False
|
|
307
|
+
yield events.AssistantTextEndEvent(
|
|
308
|
+
response_id=msg.response_id,
|
|
309
|
+
session_id=session_ctx.session_id,
|
|
310
|
+
)
|
|
273
311
|
turn_result.assistant_message = msg
|
|
274
312
|
for part in msg.parts:
|
|
275
313
|
if isinstance(part, message.ToolCallPart):
|
|
@@ -281,11 +319,16 @@ class TurnExecutor:
|
|
|
281
319
|
arguments_json=part.arguments_json,
|
|
282
320
|
)
|
|
283
321
|
)
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
322
|
+
if msg.stop_reason != "aborted":
|
|
323
|
+
thinking_text = "".join(
|
|
324
|
+
part.text for part in msg.parts if isinstance(part, message.ThinkingTextPart)
|
|
325
|
+
)
|
|
326
|
+
yield events.ResponseCompleteEvent(
|
|
327
|
+
content=message.join_text_parts(msg.parts),
|
|
328
|
+
response_id=msg.response_id,
|
|
329
|
+
session_id=session_ctx.session_id,
|
|
330
|
+
thinking_text=thinking_text or None,
|
|
331
|
+
)
|
|
289
332
|
if msg.stop_reason == "aborted":
|
|
290
333
|
yield events.InterruptEvent(session_id=session_ctx.session_id)
|
|
291
334
|
if msg.usage:
|
|
@@ -296,9 +339,9 @@ class TurnExecutor:
|
|
|
296
339
|
metadata.model_name = ctx.llm_client.model_name
|
|
297
340
|
if metadata.provider is None:
|
|
298
341
|
metadata.provider = ctx.llm_client.get_llm_config().provider_name or None
|
|
299
|
-
yield events.
|
|
342
|
+
yield events.UsageEvent(
|
|
300
343
|
session_id=session_ctx.session_id,
|
|
301
|
-
|
|
344
|
+
usage=metadata,
|
|
302
345
|
)
|
|
303
346
|
case message.StreamErrorItem() as msg:
|
|
304
347
|
turn_result.stream_error = msg
|
|
@@ -309,12 +352,23 @@ class TurnExecutor:
|
|
|
309
352
|
debug_type=DebugType.RESPONSE,
|
|
310
353
|
)
|
|
311
354
|
case message.ToolCallStartItem() as msg:
|
|
312
|
-
|
|
355
|
+
if thinking_active:
|
|
356
|
+
thinking_active = False
|
|
357
|
+
yield events.ThinkingEndEvent(
|
|
358
|
+
response_id=msg.response_id,
|
|
359
|
+
session_id=session_ctx.session_id,
|
|
360
|
+
)
|
|
361
|
+
if assistant_text_active:
|
|
362
|
+
assistant_text_active = False
|
|
363
|
+
yield events.AssistantTextEndEvent(
|
|
364
|
+
response_id=msg.response_id,
|
|
365
|
+
session_id=session_ctx.session_id,
|
|
366
|
+
)
|
|
367
|
+
yield events.ToolCallStartEvent(
|
|
313
368
|
session_id=session_ctx.session_id,
|
|
314
369
|
response_id=msg.response_id,
|
|
315
370
|
tool_call_id=msg.call_id,
|
|
316
371
|
tool_name=msg.name,
|
|
317
|
-
arguments="",
|
|
318
372
|
)
|
|
319
373
|
case _:
|
|
320
374
|
continue
|
|
@@ -332,20 +386,26 @@ class TurnExecutor:
|
|
|
332
386
|
|
|
333
387
|
ctx = self._context
|
|
334
388
|
session_ctx = ctx.session_ctx
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
389
|
+
tool_context = ToolContext(
|
|
390
|
+
file_tracker=session_ctx.file_tracker,
|
|
391
|
+
todo_context=session_ctx.todo_context,
|
|
392
|
+
session_id=session_ctx.session_id,
|
|
393
|
+
run_subtask=session_ctx.run_subtask,
|
|
394
|
+
sub_agent_resume_claims=SubAgentResumeClaims(),
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
executor = ToolExecutor(
|
|
398
|
+
context=tool_context,
|
|
399
|
+
registry=ctx.tool_registry,
|
|
400
|
+
append_history=session_ctx.append_history,
|
|
401
|
+
)
|
|
402
|
+
self._tool_executor = executor
|
|
403
|
+
try:
|
|
404
|
+
async for exec_event in executor.run_tools(tool_calls):
|
|
405
|
+
for ui_event in build_events_from_tool_executor_event(session_ctx.session_id, exec_event):
|
|
406
|
+
yield ui_event
|
|
407
|
+
finally:
|
|
408
|
+
self._tool_executor = None
|
|
349
409
|
|
|
350
410
|
def _persist_partial_assistant_on_cancel(self) -> None:
|
|
351
411
|
"""Persist streamed assistant text when a turn is interrupted.
|
|
@@ -34,8 +34,8 @@ from klaude_code.llm.client import LLMClientABC
|
|
|
34
34
|
from klaude_code.llm.input_common import apply_config_defaults
|
|
35
35
|
from klaude_code.llm.registry import register
|
|
36
36
|
from klaude_code.llm.usage import MetadataTracker, error_stream_items
|
|
37
|
+
from klaude_code.log import DebugType, log_debug
|
|
37
38
|
from klaude_code.protocol import llm_param, message, model
|
|
38
|
-
from klaude_code.trace import DebugType, log_debug
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def _map_anthropic_stop_reason(reason: str) -> model.StopReason | None:
|
|
@@ -14,8 +14,8 @@ from klaude_code.llm.client import LLMClientABC
|
|
|
14
14
|
from klaude_code.llm.input_common import apply_config_defaults
|
|
15
15
|
from klaude_code.llm.registry import register
|
|
16
16
|
from klaude_code.llm.usage import MetadataTracker, error_stream_items
|
|
17
|
+
from klaude_code.log import DebugType, log_debug
|
|
17
18
|
from klaude_code.protocol import llm_param, message
|
|
18
|
-
from klaude_code.trace import DebugType, log_debug
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
@register(llm_param.LLMClientProtocol.BEDROCK)
|
klaude_code/llm/claude/client.py
CHANGED
|
@@ -22,8 +22,8 @@ from klaude_code.llm.client import LLMClientABC
|
|
|
22
22
|
from klaude_code.llm.input_common import apply_config_defaults
|
|
23
23
|
from klaude_code.llm.registry import register
|
|
24
24
|
from klaude_code.llm.usage import MetadataTracker, error_stream_items
|
|
25
|
+
from klaude_code.log import DebugType, log_debug
|
|
25
26
|
from klaude_code.protocol import llm_param, message
|
|
26
|
-
from klaude_code.trace import DebugType, log_debug
|
|
27
27
|
|
|
28
28
|
_CLAUDE_OAUTH_REQUIRED_BETAS: tuple[str, ...] = (
|
|
29
29
|
ANTHROPIC_BETA_OAUTH,
|
klaude_code/llm/codex/client.py
CHANGED
|
@@ -25,8 +25,8 @@ from klaude_code.llm.registry import register
|
|
|
25
25
|
from klaude_code.llm.responses.client import parse_responses_stream
|
|
26
26
|
from klaude_code.llm.responses.input import convert_history_to_input, convert_tool_schema
|
|
27
27
|
from klaude_code.llm.usage import MetadataTracker, error_stream_items
|
|
28
|
+
from klaude_code.log import DebugType, log_debug
|
|
28
29
|
from klaude_code.protocol import llm_param, message
|
|
29
|
-
from klaude_code.trace import DebugType, log_debug
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def build_payload(param: llm_param.LLMCallParameter) -> ResponseCreateParamsStreaming:
|
klaude_code/llm/google/client.py
CHANGED
|
@@ -26,8 +26,8 @@ from klaude_code.llm.google.input import convert_history_to_contents, convert_to
|
|
|
26
26
|
from klaude_code.llm.input_common import apply_config_defaults
|
|
27
27
|
from klaude_code.llm.registry import register
|
|
28
28
|
from klaude_code.llm.usage import MetadataTracker
|
|
29
|
+
from klaude_code.log import DebugType, log_debug
|
|
29
30
|
from klaude_code.protocol import llm_param, message, model
|
|
30
|
-
from klaude_code.trace import DebugType, log_debug
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def _build_config(param: llm_param.LLMCallParameter) -> GenerateContentConfig:
|
|
@@ -13,8 +13,8 @@ from klaude_code.llm.openai_compatible.input import convert_history_to_input, co
|
|
|
13
13
|
from klaude_code.llm.openai_compatible.stream import DefaultReasoningHandler, parse_chat_completions_stream
|
|
14
14
|
from klaude_code.llm.registry import register
|
|
15
15
|
from klaude_code.llm.usage import MetadataTracker
|
|
16
|
+
from klaude_code.log import DebugType, log_debug
|
|
16
17
|
from klaude_code.protocol import llm_param, message
|
|
17
|
-
from klaude_code.trace import DebugType, log_debug
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def build_payload(param: llm_param.LLMCallParameter) -> tuple[CompletionCreateParamsStreaming, dict[str, object]]:
|
|
@@ -4,8 +4,8 @@ from abc import ABC, abstractmethod
|
|
|
4
4
|
from openai.types.chat.chat_completion_chunk import ChoiceDeltaToolCall
|
|
5
5
|
from pydantic import BaseModel, Field
|
|
6
6
|
|
|
7
|
+
from klaude_code.log import log_debug
|
|
7
8
|
from klaude_code.protocol import message
|
|
8
|
-
from klaude_code.trace.log import log_debug
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def normalize_tool_name(name: str) -> str:
|
|
@@ -22,8 +22,8 @@ from klaude_code.llm.openrouter.input import convert_history_to_input, is_claude
|
|
|
22
22
|
from klaude_code.llm.openrouter.reasoning import ReasoningStreamHandler
|
|
23
23
|
from klaude_code.llm.registry import register
|
|
24
24
|
from klaude_code.llm.usage import MetadataTracker
|
|
25
|
+
from klaude_code.log import DebugType, is_debug_enabled, log_debug
|
|
25
26
|
from klaude_code.protocol import llm_param, message
|
|
26
|
-
from klaude_code.trace import DebugType, is_debug_enabled, log_debug
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
def build_payload(
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from pydantic import BaseModel
|
|
2
2
|
|
|
3
3
|
from klaude_code.llm.openai_compatible.stream import ReasoningDeltaResult, ReasoningHandlerABC
|
|
4
|
+
from klaude_code.log import log
|
|
4
5
|
from klaude_code.protocol import message
|
|
5
|
-
from klaude_code.trace import log
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class ReasoningDetail(BaseModel):
|
|
@@ -14,8 +14,8 @@ from klaude_code.llm.input_common import apply_config_defaults
|
|
|
14
14
|
from klaude_code.llm.registry import register
|
|
15
15
|
from klaude_code.llm.responses.input import convert_history_to_input, convert_tool_schema
|
|
16
16
|
from klaude_code.llm.usage import MetadataTracker, error_stream_items
|
|
17
|
+
from klaude_code.log import DebugType, log_debug
|
|
17
18
|
from klaude_code.protocol import llm_param, message, model
|
|
18
|
-
from klaude_code.trace import DebugType, log_debug
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
21
21
|
from openai import AsyncStream
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from klaude_code.protocol.events.base import Event, ResponseEvent
|
|
4
|
+
from klaude_code.protocol.events.chat import DeveloperMessageEvent, TodoChangeEvent, UserMessageEvent
|
|
5
|
+
from klaude_code.protocol.events.lifecycle import TaskFinishEvent, TaskStartEvent, TurnEndEvent, TurnStartEvent
|
|
6
|
+
from klaude_code.protocol.events.metadata import TaskMetadataEvent, UsageEvent
|
|
7
|
+
from klaude_code.protocol.events.streaming import (
|
|
8
|
+
AssistantImageDeltaEvent,
|
|
9
|
+
AssistantTextDeltaEvent,
|
|
10
|
+
AssistantTextEndEvent,
|
|
11
|
+
AssistantTextStartEvent,
|
|
12
|
+
ResponseCompleteEvent,
|
|
13
|
+
ThinkingDeltaEvent,
|
|
14
|
+
ThinkingEndEvent,
|
|
15
|
+
ThinkingStartEvent,
|
|
16
|
+
ToolCallStartEvent,
|
|
17
|
+
)
|
|
18
|
+
from klaude_code.protocol.events.system import (
|
|
19
|
+
EndEvent,
|
|
20
|
+
ErrorEvent,
|
|
21
|
+
InterruptEvent,
|
|
22
|
+
ReplayEventUnion,
|
|
23
|
+
ReplayHistoryEvent,
|
|
24
|
+
WelcomeEvent,
|
|
25
|
+
)
|
|
26
|
+
from klaude_code.protocol.events.tools import ToolCallEvent, ToolResultEvent
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"AssistantImageDeltaEvent",
|
|
30
|
+
"AssistantTextDeltaEvent",
|
|
31
|
+
"AssistantTextEndEvent",
|
|
32
|
+
"AssistantTextStartEvent",
|
|
33
|
+
"DeveloperMessageEvent",
|
|
34
|
+
"EndEvent",
|
|
35
|
+
"ErrorEvent",
|
|
36
|
+
"Event",
|
|
37
|
+
"InterruptEvent",
|
|
38
|
+
"ReplayEventUnion",
|
|
39
|
+
"ReplayHistoryEvent",
|
|
40
|
+
"ResponseCompleteEvent",
|
|
41
|
+
"ResponseEvent",
|
|
42
|
+
"TaskFinishEvent",
|
|
43
|
+
"TaskMetadataEvent",
|
|
44
|
+
"TaskStartEvent",
|
|
45
|
+
"ThinkingDeltaEvent",
|
|
46
|
+
"ThinkingEndEvent",
|
|
47
|
+
"ThinkingStartEvent",
|
|
48
|
+
"TodoChangeEvent",
|
|
49
|
+
"ToolCallEvent",
|
|
50
|
+
"ToolCallStartEvent",
|
|
51
|
+
"ToolResultEvent",
|
|
52
|
+
"TurnEndEvent",
|
|
53
|
+
"TurnStartEvent",
|
|
54
|
+
"UsageEvent",
|
|
55
|
+
"UserMessageEvent",
|
|
56
|
+
"WelcomeEvent",
|
|
57
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Event(BaseModel):
|
|
9
|
+
"""Base event."""
|
|
10
|
+
|
|
11
|
+
session_id: str
|
|
12
|
+
timestamp: float = Field(default_factory=time.time)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ResponseEvent(Event):
|
|
16
|
+
"""Event associated with a single model response."""
|
|
17
|
+
|
|
18
|
+
response_id: str | None = None
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from klaude_code.protocol import message, model
|
|
4
|
+
|
|
5
|
+
from .base import Event
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class UserMessageEvent(Event):
|
|
9
|
+
content: str
|
|
10
|
+
images: list[message.ImageURLPart] | None = None
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DeveloperMessageEvent(Event):
|
|
14
|
+
"""DeveloperMessages are reminders in user messages or tool results."""
|
|
15
|
+
|
|
16
|
+
item: message.DeveloperMessage
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TodoChangeEvent(Event):
|
|
20
|
+
todos: list[model.TodoItem]
|