klaude-code 2.0.2__py3-none-any.whl → 2.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. klaude_code/app/__init__.py +12 -0
  2. klaude_code/app/runtime.py +215 -0
  3. klaude_code/cli/auth_cmd.py +2 -2
  4. klaude_code/cli/config_cmd.py +2 -2
  5. klaude_code/cli/cost_cmd.py +1 -1
  6. klaude_code/cli/debug.py +12 -36
  7. klaude_code/cli/list_model.py +3 -3
  8. klaude_code/cli/main.py +17 -60
  9. klaude_code/cli/self_update.py +2 -187
  10. klaude_code/cli/session_cmd.py +2 -2
  11. klaude_code/config/config.py +1 -1
  12. klaude_code/config/select_model.py +1 -1
  13. klaude_code/const.py +9 -1
  14. klaude_code/core/agent.py +9 -62
  15. klaude_code/core/agent_profile.py +291 -0
  16. klaude_code/core/executor.py +335 -230
  17. klaude_code/core/manager/llm_clients_builder.py +1 -1
  18. klaude_code/core/manager/sub_agent_manager.py +16 -29
  19. klaude_code/core/reminders.py +84 -103
  20. klaude_code/core/task.py +12 -20
  21. klaude_code/core/tool/__init__.py +5 -19
  22. klaude_code/core/tool/context.py +84 -0
  23. klaude_code/core/tool/file/apply_patch_tool.py +18 -21
  24. klaude_code/core/tool/file/edit_tool.py +39 -42
  25. klaude_code/core/tool/file/read_tool.py +14 -9
  26. klaude_code/core/tool/file/write_tool.py +12 -13
  27. klaude_code/core/tool/report_back_tool.py +4 -1
  28. klaude_code/core/tool/shell/bash_tool.py +6 -11
  29. klaude_code/core/tool/sub_agent_tool.py +8 -7
  30. klaude_code/core/tool/todo/todo_write_tool.py +3 -9
  31. klaude_code/core/tool/todo/update_plan_tool.py +3 -5
  32. klaude_code/core/tool/tool_abc.py +2 -1
  33. klaude_code/core/tool/tool_registry.py +2 -33
  34. klaude_code/core/tool/tool_runner.py +13 -10
  35. klaude_code/core/tool/web/mermaid_tool.py +3 -1
  36. klaude_code/core/tool/web/web_fetch_tool.py +5 -3
  37. klaude_code/core/tool/web/web_search_tool.py +5 -3
  38. klaude_code/core/turn.py +87 -30
  39. klaude_code/llm/anthropic/client.py +1 -1
  40. klaude_code/llm/bedrock/client.py +1 -1
  41. klaude_code/llm/claude/client.py +1 -1
  42. klaude_code/llm/codex/client.py +1 -1
  43. klaude_code/llm/google/client.py +1 -1
  44. klaude_code/llm/openai_compatible/client.py +1 -1
  45. klaude_code/llm/openai_compatible/tool_call_accumulator.py +1 -1
  46. klaude_code/llm/openrouter/client.py +1 -1
  47. klaude_code/llm/openrouter/reasoning.py +1 -1
  48. klaude_code/llm/responses/client.py +1 -1
  49. klaude_code/protocol/commands.py +1 -0
  50. klaude_code/protocol/events/__init__.py +57 -0
  51. klaude_code/protocol/events/base.py +18 -0
  52. klaude_code/protocol/events/chat.py +20 -0
  53. klaude_code/protocol/events/lifecycle.py +22 -0
  54. klaude_code/protocol/events/metadata.py +15 -0
  55. klaude_code/protocol/events/streaming.py +43 -0
  56. klaude_code/protocol/events/system.py +53 -0
  57. klaude_code/protocol/events/tools.py +27 -0
  58. klaude_code/protocol/op.py +5 -0
  59. klaude_code/protocol/tools.py +0 -1
  60. klaude_code/session/session.py +6 -7
  61. klaude_code/skill/assets/create-plan/SKILL.md +76 -0
  62. klaude_code/skill/loader.py +32 -88
  63. klaude_code/skill/manager.py +38 -0
  64. klaude_code/skill/system_skills.py +1 -1
  65. klaude_code/tui/__init__.py +8 -0
  66. klaude_code/{command → tui/command}/__init__.py +3 -0
  67. klaude_code/{command → tui/command}/clear_cmd.py +2 -1
  68. klaude_code/tui/command/copy_cmd.py +53 -0
  69. klaude_code/{command → tui/command}/debug_cmd.py +3 -2
  70. klaude_code/{command → tui/command}/export_cmd.py +2 -1
  71. klaude_code/{command → tui/command}/export_online_cmd.py +2 -1
  72. klaude_code/{command → tui/command}/fork_session_cmd.py +4 -3
  73. klaude_code/{command → tui/command}/help_cmd.py +2 -1
  74. klaude_code/{command → tui/command}/model_cmd.py +4 -3
  75. klaude_code/{command → tui/command}/model_select.py +2 -2
  76. klaude_code/{command → tui/command}/prompt_command.py +4 -3
  77. klaude_code/{command → tui/command}/refresh_cmd.py +3 -1
  78. klaude_code/{command → tui/command}/registry.py +6 -5
  79. klaude_code/{command → tui/command}/release_notes_cmd.py +2 -1
  80. klaude_code/{command → tui/command}/resume_cmd.py +4 -3
  81. klaude_code/{command → tui/command}/status_cmd.py +2 -1
  82. klaude_code/{command → tui/command}/terminal_setup_cmd.py +2 -1
  83. klaude_code/{command → tui/command}/thinking_cmd.py +3 -2
  84. klaude_code/tui/commands.py +164 -0
  85. klaude_code/{ui/renderers → tui/components}/assistant.py +3 -3
  86. klaude_code/{ui/renderers → tui/components}/bash_syntax.py +2 -2
  87. klaude_code/{ui/renderers → tui/components}/common.py +1 -1
  88. klaude_code/{ui/renderers → tui/components}/developer.py +4 -4
  89. klaude_code/{ui/renderers → tui/components}/diffs.py +2 -2
  90. klaude_code/{ui/renderers → tui/components}/errors.py +2 -2
  91. klaude_code/{ui/renderers → tui/components}/metadata.py +7 -7
  92. klaude_code/{ui → tui/components}/rich/markdown.py +9 -23
  93. klaude_code/{ui → tui/components}/rich/status.py +2 -2
  94. klaude_code/{ui → tui/components}/rich/theme.py +3 -1
  95. klaude_code/{ui/renderers → tui/components}/sub_agent.py +23 -43
  96. klaude_code/{ui/renderers → tui/components}/thinking.py +3 -3
  97. klaude_code/{ui/renderers → tui/components}/tools.py +13 -17
  98. klaude_code/{ui/renderers → tui/components}/user_input.py +3 -20
  99. klaude_code/tui/display.py +85 -0
  100. klaude_code/{ui/modes/repl → tui/input}/__init__.py +1 -1
  101. klaude_code/{ui/modes/repl → tui/input}/completers.py +1 -1
  102. klaude_code/{ui/modes/repl/input_prompt_toolkit.py → tui/input/prompt_toolkit.py} +6 -6
  103. klaude_code/tui/machine.py +608 -0
  104. klaude_code/tui/renderer.py +707 -0
  105. klaude_code/tui/runner.py +321 -0
  106. klaude_code/tui/terminal/__init__.py +56 -0
  107. klaude_code/{ui → tui}/terminal/color.py +1 -1
  108. klaude_code/{ui → tui}/terminal/control.py +1 -1
  109. klaude_code/{ui → tui}/terminal/notifier.py +1 -1
  110. klaude_code/ui/__init__.py +6 -50
  111. klaude_code/ui/core/display.py +3 -3
  112. klaude_code/ui/core/input.py +2 -1
  113. klaude_code/ui/{modes/debug/display.py → debug_mode.py} +1 -1
  114. klaude_code/ui/{modes/exec/display.py → exec_mode.py} +0 -2
  115. klaude_code/ui/terminal/__init__.py +6 -54
  116. klaude_code/ui/terminal/title.py +31 -0
  117. klaude_code/update.py +163 -0
  118. {klaude_code-2.0.2.dist-info → klaude_code-2.1.1.dist-info}/METADATA +1 -1
  119. klaude_code-2.1.1.dist-info/RECORD +233 -0
  120. klaude_code/cli/runtime.py +0 -518
  121. klaude_code/core/prompt.py +0 -108
  122. klaude_code/core/tool/skill/skill_tool.md +0 -24
  123. klaude_code/core/tool/skill/skill_tool.py +0 -87
  124. klaude_code/core/tool/tool_context.py +0 -148
  125. klaude_code/protocol/events.py +0 -195
  126. klaude_code/skill/assets/dev-docs/SKILL.md +0 -108
  127. klaude_code/trace/__init__.py +0 -21
  128. klaude_code/ui/core/stage_manager.py +0 -48
  129. klaude_code/ui/modes/__init__.py +0 -1
  130. klaude_code/ui/modes/debug/__init__.py +0 -1
  131. klaude_code/ui/modes/exec/__init__.py +0 -1
  132. klaude_code/ui/modes/repl/display.py +0 -61
  133. klaude_code/ui/modes/repl/event_handler.py +0 -629
  134. klaude_code/ui/modes/repl/renderer.py +0 -464
  135. klaude_code/ui/renderers/__init__.py +0 -0
  136. klaude_code/ui/utils/__init__.py +0 -1
  137. klaude_code-2.0.2.dist-info/RECORD +0 -227
  138. /klaude_code/{trace/log.py → log.py} +0 -0
  139. /klaude_code/{command → tui/command}/command_abc.py +0 -0
  140. /klaude_code/{command → tui/command}/prompt-commit.md +0 -0
  141. /klaude_code/{command → tui/command}/prompt-init.md +0 -0
  142. /klaude_code/{core/tool/skill → tui/components}/__init__.py +0 -0
  143. /klaude_code/{ui/renderers → tui/components}/mermaid_viewer.py +0 -0
  144. /klaude_code/{ui → tui/components}/rich/__init__.py +0 -0
  145. /klaude_code/{ui → tui/components}/rich/cjk_wrap.py +0 -0
  146. /klaude_code/{ui → tui/components}/rich/code_panel.py +0 -0
  147. /klaude_code/{ui → tui/components}/rich/live.py +0 -0
  148. /klaude_code/{ui → tui/components}/rich/quote.py +0 -0
  149. /klaude_code/{ui → tui/components}/rich/searchable_text.py +0 -0
  150. /klaude_code/{ui/modes/repl → tui/input}/clipboard.py +0 -0
  151. /klaude_code/{ui/modes/repl → tui/input}/key_bindings.py +0 -0
  152. /klaude_code/{ui → tui}/terminal/image.py +0 -0
  153. /klaude_code/{ui → tui}/terminal/progress_bar.py +0 -0
  154. /klaude_code/{ui → tui}/terminal/selector.py +0 -0
  155. /klaude_code/ui/{utils/common.py → common.py} +0 -0
  156. {klaude_code-2.0.2.dist-info → klaude_code-2.1.1.dist-info}/WHEEL +0 -0
  157. {klaude_code-2.0.2.dist-info → klaude_code-2.1.1.dist-info}/entry_points.txt +0 -0
@@ -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, tool_context
9
- from klaude_code.core.tool.tool_context import current_sub_agent_resume_claims
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):
@@ -69,7 +69,6 @@ def build_events_from_tool_executor_event(session_id: str, event: ToolExecutorEv
69
69
  )
70
70
  )
71
71
  case ToolExecutionResult(tool_call=tool_call, tool_result=tool_result, is_last_in_turn=is_last_in_turn):
72
- status = "success" if tool_result.status == "success" else "error"
73
72
  ui_events.append(
74
73
  events.ToolResultEvent(
75
74
  session_id=session_id,
@@ -78,13 +77,11 @@ def build_events_from_tool_executor_event(session_id: str, event: ToolExecutorEv
78
77
  tool_name=tool_call.tool_name,
79
78
  result=tool_result.output_text,
80
79
  ui_extra=tool_result.ui_extra,
81
- status=status,
80
+ status=tool_result.status,
82
81
  task_metadata=tool_result.task_metadata,
83
82
  is_last_in_turn=is_last_in_turn,
84
83
  )
85
84
  )
86
- if tool_result.status == "aborted":
87
- ui_events.append(events.InterruptEvent(session_id=session_id))
88
85
  case ToolExecutionTodoChange(todos=todos):
89
86
  ui_events.append(
90
87
  events.TodoChangeEvent(
@@ -206,6 +203,8 @@ class TurnExecutor:
206
203
 
207
204
  ctx = self._context
208
205
  session_ctx = ctx.session_ctx
206
+ thinking_active = False
207
+ assistant_text_active = False
209
208
  message_types = (
210
209
  message.SystemMessage,
211
210
  message.DeveloperMessage,
@@ -247,12 +246,30 @@ class TurnExecutor:
247
246
  )
248
247
  match delta:
249
248
  case message.ThinkingTextDelta() as delta:
249
+ if not thinking_active:
250
+ thinking_active = True
251
+ yield events.ThinkingStartEvent(
252
+ response_id=delta.response_id,
253
+ session_id=session_ctx.session_id,
254
+ )
250
255
  yield events.ThinkingDeltaEvent(
251
256
  content=delta.content,
252
257
  response_id=delta.response_id,
253
258
  session_id=session_ctx.session_id,
254
259
  )
255
260
  case message.AssistantTextDelta() as delta:
261
+ if thinking_active:
262
+ thinking_active = False
263
+ yield events.ThinkingEndEvent(
264
+ response_id=delta.response_id,
265
+ session_id=session_ctx.session_id,
266
+ )
267
+ if not assistant_text_active:
268
+ assistant_text_active = True
269
+ yield events.AssistantTextStartEvent(
270
+ response_id=delta.response_id,
271
+ session_id=session_ctx.session_id,
272
+ )
256
273
  if delta.response_id:
257
274
  self._assistant_response_id = delta.response_id
258
275
  self._assistant_delta_buffer.append(delta.content)
@@ -262,6 +279,12 @@ class TurnExecutor:
262
279
  session_id=session_ctx.session_id,
263
280
  )
264
281
  case message.AssistantImageDelta() as delta:
282
+ if thinking_active:
283
+ thinking_active = False
284
+ yield events.ThinkingEndEvent(
285
+ response_id=delta.response_id,
286
+ session_id=session_ctx.session_id,
287
+ )
265
288
  yield events.AssistantImageDeltaEvent(
266
289
  file_path=delta.file_path,
267
290
  response_id=delta.response_id,
@@ -270,6 +293,18 @@ class TurnExecutor:
270
293
  case message.AssistantMessage() as msg:
271
294
  if msg.response_id is None and self._assistant_response_id:
272
295
  msg.response_id = self._assistant_response_id
296
+ if thinking_active:
297
+ thinking_active = False
298
+ yield events.ThinkingEndEvent(
299
+ response_id=msg.response_id,
300
+ session_id=session_ctx.session_id,
301
+ )
302
+ if assistant_text_active:
303
+ assistant_text_active = False
304
+ yield events.AssistantTextEndEvent(
305
+ response_id=msg.response_id,
306
+ session_id=session_ctx.session_id,
307
+ )
273
308
  turn_result.assistant_message = msg
274
309
  for part in msg.parts:
275
310
  if isinstance(part, message.ToolCallPart):
@@ -281,11 +316,16 @@ class TurnExecutor:
281
316
  arguments_json=part.arguments_json,
282
317
  )
283
318
  )
284
- yield events.AssistantMessageEvent(
285
- content=message.join_text_parts(msg.parts),
286
- response_id=msg.response_id,
287
- session_id=session_ctx.session_id,
288
- )
319
+ if msg.stop_reason != "aborted":
320
+ thinking_text = "".join(
321
+ part.text for part in msg.parts if isinstance(part, message.ThinkingTextPart)
322
+ )
323
+ yield events.ResponseCompleteEvent(
324
+ content=message.join_text_parts(msg.parts),
325
+ response_id=msg.response_id,
326
+ session_id=session_ctx.session_id,
327
+ thinking_text=thinking_text or None,
328
+ )
289
329
  if msg.stop_reason == "aborted":
290
330
  yield events.InterruptEvent(session_id=session_ctx.session_id)
291
331
  if msg.usage:
@@ -296,9 +336,9 @@ class TurnExecutor:
296
336
  metadata.model_name = ctx.llm_client.model_name
297
337
  if metadata.provider is None:
298
338
  metadata.provider = ctx.llm_client.get_llm_config().provider_name or None
299
- yield events.ResponseMetadataEvent(
339
+ yield events.UsageEvent(
300
340
  session_id=session_ctx.session_id,
301
- metadata=metadata,
341
+ usage=metadata,
302
342
  )
303
343
  case message.StreamErrorItem() as msg:
304
344
  turn_result.stream_error = msg
@@ -309,12 +349,23 @@ class TurnExecutor:
309
349
  debug_type=DebugType.RESPONSE,
310
350
  )
311
351
  case message.ToolCallStartItem() as msg:
312
- yield events.TurnToolCallStartEvent(
352
+ if thinking_active:
353
+ thinking_active = False
354
+ yield events.ThinkingEndEvent(
355
+ response_id=msg.response_id,
356
+ session_id=session_ctx.session_id,
357
+ )
358
+ if assistant_text_active:
359
+ assistant_text_active = False
360
+ yield events.AssistantTextEndEvent(
361
+ response_id=msg.response_id,
362
+ session_id=session_ctx.session_id,
363
+ )
364
+ yield events.ToolCallStartEvent(
313
365
  session_id=session_ctx.session_id,
314
366
  response_id=msg.response_id,
315
367
  tool_call_id=msg.call_id,
316
368
  tool_name=msg.name,
317
- arguments="",
318
369
  )
319
370
  case _:
320
371
  continue
@@ -332,20 +383,26 @@ class TurnExecutor:
332
383
 
333
384
  ctx = self._context
334
385
  session_ctx = ctx.session_ctx
335
- with tool_context(session_ctx.file_tracker, session_ctx.todo_context):
336
- resume_claims_token = current_sub_agent_resume_claims.set(set())
337
- executor = ToolExecutor(
338
- registry=ctx.tool_registry,
339
- append_history=session_ctx.append_history,
340
- )
341
- self._tool_executor = executor
342
- try:
343
- async for exec_event in executor.run_tools(tool_calls):
344
- for ui_event in build_events_from_tool_executor_event(session_ctx.session_id, exec_event):
345
- yield ui_event
346
- finally:
347
- self._tool_executor = None
348
- current_sub_agent_resume_claims.reset(resume_claims_token)
386
+ tool_context = ToolContext(
387
+ file_tracker=session_ctx.file_tracker,
388
+ todo_context=session_ctx.todo_context,
389
+ session_id=session_ctx.session_id,
390
+ run_subtask=session_ctx.run_subtask,
391
+ sub_agent_resume_claims=SubAgentResumeClaims(),
392
+ )
393
+
394
+ executor = ToolExecutor(
395
+ context=tool_context,
396
+ registry=ctx.tool_registry,
397
+ append_history=session_ctx.append_history,
398
+ )
399
+ self._tool_executor = executor
400
+ try:
401
+ async for exec_event in executor.run_tools(tool_calls):
402
+ for ui_event in build_events_from_tool_executor_event(session_ctx.session_id, exec_event):
403
+ yield ui_event
404
+ finally:
405
+ self._tool_executor = None
349
406
 
350
407
  def _persist_partial_assistant_on_cancel(self) -> None:
351
408
  """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)
@@ -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,
@@ -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:
@@ -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
@@ -28,6 +28,7 @@ class CommandName(str, Enum):
28
28
  THINKING = "thinking"
29
29
  FORK_SESSION = "fork-session"
30
30
  RESUME = "resume"
31
+ COPY = "copy"
31
32
  # PLAN and DOC are dynamically registered now, but kept here if needed for reference
32
33
  # or we can remove them if no code explicitly imports them.
33
34
  # PLAN = "plan"
@@ -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]
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ from klaude_code.protocol import model
4
+
5
+ from .base import Event
6
+
7
+
8
+ class TaskStartEvent(Event):
9
+ sub_agent_state: model.SubAgentState | None = None
10
+
11
+
12
+ class TaskFinishEvent(Event):
13
+ task_result: str
14
+ has_structured_output: bool = False
15
+
16
+
17
+ class TurnStartEvent(Event):
18
+ pass
19
+
20
+
21
+ class TurnEndEvent(Event):
22
+ pass
@@ -0,0 +1,15 @@
1
+ """Metadata-related protocol events."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from klaude_code.protocol import model
6
+
7
+ from .base import Event, ResponseEvent
8
+
9
+
10
+ class UsageEvent(ResponseEvent):
11
+ usage: model.Usage
12
+
13
+
14
+ class TaskMetadataEvent(Event):
15
+ metadata: model.TaskMetadataItem
@@ -0,0 +1,43 @@
1
+ from __future__ import annotations
2
+
3
+ from .base import ResponseEvent
4
+
5
+
6
+ class ThinkingStartEvent(ResponseEvent):
7
+ pass
8
+
9
+
10
+ class ThinkingDeltaEvent(ResponseEvent):
11
+ content: str
12
+
13
+
14
+ class ThinkingEndEvent(ResponseEvent):
15
+ pass
16
+
17
+
18
+ class AssistantTextStartEvent(ResponseEvent):
19
+ pass
20
+
21
+
22
+ class AssistantTextDeltaEvent(ResponseEvent):
23
+ content: str
24
+
25
+
26
+ class AssistantTextEndEvent(ResponseEvent):
27
+ pass
28
+
29
+
30
+ class AssistantImageDeltaEvent(ResponseEvent):
31
+ file_path: str
32
+
33
+
34
+ class ToolCallStartEvent(ResponseEvent):
35
+ tool_call_id: str
36
+ tool_name: str
37
+
38
+
39
+ class ResponseCompleteEvent(ResponseEvent):
40
+ """Final snapshot of the model response."""
41
+
42
+ content: str
43
+ thinking_text: str | None = None
@@ -0,0 +1,53 @@
1
+ from __future__ import annotations
2
+
3
+ from klaude_code.protocol import llm_param
4
+ from klaude_code.protocol.events.chat import DeveloperMessageEvent, UserMessageEvent
5
+ from klaude_code.protocol.events.lifecycle import TaskFinishEvent, TaskStartEvent, TurnStartEvent
6
+ from klaude_code.protocol.events.metadata import TaskMetadataEvent
7
+ from klaude_code.protocol.events.streaming import AssistantImageDeltaEvent, ResponseCompleteEvent
8
+ from klaude_code.protocol.events.tools import ToolCallEvent, ToolResultEvent
9
+
10
+ from .base import Event
11
+
12
+
13
+ class WelcomeEvent(Event):
14
+ work_dir: str
15
+ llm_config: llm_param.LLMConfigParameter
16
+ show_klaude_code_info: bool = True
17
+
18
+
19
+ class ErrorEvent(Event):
20
+ error_message: str
21
+ can_retry: bool = False
22
+
23
+
24
+ class InterruptEvent(Event):
25
+ pass
26
+
27
+
28
+ class EndEvent(Event):
29
+ """Global display shutdown."""
30
+
31
+ session_id: str = "__app__"
32
+
33
+
34
+ type ReplayEventUnion = (
35
+ TaskStartEvent
36
+ | TaskFinishEvent
37
+ | TurnStartEvent
38
+ | AssistantImageDeltaEvent
39
+ | ResponseCompleteEvent
40
+ | ToolCallEvent
41
+ | ToolResultEvent
42
+ | UserMessageEvent
43
+ | TaskMetadataEvent
44
+ | InterruptEvent
45
+ | DeveloperMessageEvent
46
+ | ErrorEvent
47
+ )
48
+
49
+
50
+ class ReplayHistoryEvent(Event):
51
+ events: list[ReplayEventUnion]
52
+ updated_at: float
53
+ is_load: bool = True
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Literal
4
+
5
+ from klaude_code.protocol import model
6
+
7
+ from .base import ResponseEvent
8
+
9
+
10
+ class ToolCallEvent(ResponseEvent):
11
+ tool_call_id: str
12
+ tool_name: str
13
+ arguments: str
14
+
15
+
16
+ class ToolResultEvent(ResponseEvent):
17
+ tool_call_id: str
18
+ tool_name: str
19
+ result: str
20
+ ui_extra: model.ToolResultUIExtra | None = None
21
+ status: Literal["success", "error", "aborted"]
22
+ task_metadata: model.TaskMetadata | None = None
23
+ is_last_in_turn: bool = True
24
+
25
+ @property
26
+ def is_error(self) -> bool:
27
+ return self.status in ("error", "aborted")
@@ -51,6 +51,11 @@ class RunAgentOperation(Operation):
51
51
  type: OperationType = OperationType.RUN_AGENT
52
52
  session_id: str
53
53
  input: UserInputPayload
54
+ # Frontends may choose to render the user message themselves (e.g. TUI) to support
55
+ # event-only commands; in that case the core should skip emitting the UserMessageEvent.
56
+ emit_user_message_event: bool = True
57
+ # Frontends may choose to run without persisting input (e.g. some interactive commands).
58
+ persist_user_input: bool = True
54
59
 
55
60
  async def execute(self, handler: OperationHandler) -> None:
56
61
  await handler.handle_run_agent(self)
@@ -6,7 +6,6 @@ READ = "Read"
6
6
  WRITE = "Write"
7
7
  TODO_WRITE = "TodoWrite"
8
8
  UPDATE_PLAN = "update_plan"
9
- SKILL = "Skill"
10
9
  MERMAID = "Mermaid"
11
10
  WEB_FETCH = "WebFetch"
12
11
  WEB_SEARCH = "WebSearch"