klaude-code 2.0.2__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.
Files changed (151) 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 +284 -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 +64 -99
  20. klaude_code/core/task.py +12 -20
  21. klaude_code/core/tool/__init__.py +5 -17
  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/skill/skill_tool.py +3 -1
  30. klaude_code/core/tool/sub_agent_tool.py +8 -7
  31. klaude_code/core/tool/todo/todo_write_tool.py +3 -9
  32. klaude_code/core/tool/todo/update_plan_tool.py +3 -5
  33. klaude_code/core/tool/tool_abc.py +2 -1
  34. klaude_code/core/tool/tool_registry.py +2 -33
  35. klaude_code/core/tool/tool_runner.py +13 -10
  36. klaude_code/core/tool/web/mermaid_tool.py +3 -1
  37. klaude_code/core/tool/web/web_fetch_tool.py +5 -3
  38. klaude_code/core/tool/web/web_search_tool.py +5 -3
  39. klaude_code/core/turn.py +86 -26
  40. klaude_code/llm/anthropic/client.py +1 -1
  41. klaude_code/llm/bedrock/client.py +1 -1
  42. klaude_code/llm/claude/client.py +1 -1
  43. klaude_code/llm/codex/client.py +1 -1
  44. klaude_code/llm/google/client.py +1 -1
  45. klaude_code/llm/openai_compatible/client.py +1 -1
  46. klaude_code/llm/openai_compatible/tool_call_accumulator.py +1 -1
  47. klaude_code/llm/openrouter/client.py +1 -1
  48. klaude_code/llm/openrouter/reasoning.py +1 -1
  49. klaude_code/llm/responses/client.py +1 -1
  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 +23 -0
  58. klaude_code/protocol/op.py +5 -0
  59. klaude_code/session/session.py +6 -5
  60. klaude_code/skill/assets/create-plan/SKILL.md +76 -0
  61. klaude_code/skill/loader.py +1 -1
  62. klaude_code/skill/system_skills.py +1 -1
  63. klaude_code/tui/__init__.py +8 -0
  64. klaude_code/{command → tui/command}/clear_cmd.py +2 -1
  65. klaude_code/{command → tui/command}/debug_cmd.py +3 -2
  66. klaude_code/{command → tui/command}/export_cmd.py +2 -1
  67. klaude_code/{command → tui/command}/export_online_cmd.py +2 -1
  68. klaude_code/{command → tui/command}/fork_session_cmd.py +4 -3
  69. klaude_code/{command → tui/command}/help_cmd.py +2 -1
  70. klaude_code/{command → tui/command}/model_cmd.py +4 -3
  71. klaude_code/{command → tui/command}/model_select.py +2 -2
  72. klaude_code/{command → tui/command}/prompt_command.py +4 -3
  73. klaude_code/{command → tui/command}/refresh_cmd.py +3 -1
  74. klaude_code/{command → tui/command}/registry.py +6 -5
  75. klaude_code/{command → tui/command}/release_notes_cmd.py +2 -1
  76. klaude_code/{command → tui/command}/resume_cmd.py +4 -3
  77. klaude_code/{command → tui/command}/status_cmd.py +2 -1
  78. klaude_code/{command → tui/command}/terminal_setup_cmd.py +2 -1
  79. klaude_code/{command → tui/command}/thinking_cmd.py +3 -2
  80. klaude_code/tui/commands.py +164 -0
  81. klaude_code/{ui/renderers → tui/components}/assistant.py +3 -3
  82. klaude_code/{ui/renderers → tui/components}/bash_syntax.py +2 -2
  83. klaude_code/{ui/renderers → tui/components}/common.py +1 -1
  84. klaude_code/{ui/renderers → tui/components}/developer.py +4 -4
  85. klaude_code/{ui/renderers → tui/components}/diffs.py +2 -2
  86. klaude_code/{ui/renderers → tui/components}/errors.py +2 -2
  87. klaude_code/{ui/renderers → tui/components}/metadata.py +7 -7
  88. klaude_code/{ui → tui/components}/rich/markdown.py +9 -23
  89. klaude_code/{ui → tui/components}/rich/status.py +2 -2
  90. klaude_code/{ui → tui/components}/rich/theme.py +3 -1
  91. klaude_code/{ui/renderers → tui/components}/sub_agent.py +23 -43
  92. klaude_code/{ui/renderers → tui/components}/thinking.py +3 -3
  93. klaude_code/{ui/renderers → tui/components}/tools.py +9 -9
  94. klaude_code/{ui/renderers → tui/components}/user_input.py +3 -20
  95. klaude_code/tui/display.py +85 -0
  96. klaude_code/{ui/modes/repl → tui/input}/__init__.py +1 -1
  97. klaude_code/{ui/modes/repl → tui/input}/completers.py +1 -1
  98. klaude_code/{ui/modes/repl/input_prompt_toolkit.py → tui/input/prompt_toolkit.py} +6 -6
  99. klaude_code/tui/machine.py +606 -0
  100. klaude_code/tui/renderer.py +707 -0
  101. klaude_code/tui/runner.py +321 -0
  102. klaude_code/tui/terminal/__init__.py +56 -0
  103. klaude_code/{ui → tui}/terminal/color.py +1 -1
  104. klaude_code/{ui → tui}/terminal/control.py +1 -1
  105. klaude_code/{ui → tui}/terminal/notifier.py +1 -1
  106. klaude_code/ui/__init__.py +6 -50
  107. klaude_code/ui/core/display.py +3 -3
  108. klaude_code/ui/core/input.py +2 -1
  109. klaude_code/ui/{modes/debug/display.py → debug_mode.py} +1 -1
  110. klaude_code/ui/{modes/exec/display.py → exec_mode.py} +0 -2
  111. klaude_code/ui/terminal/__init__.py +6 -54
  112. klaude_code/ui/terminal/title.py +31 -0
  113. klaude_code/update.py +163 -0
  114. {klaude_code-2.0.2.dist-info → klaude_code-2.1.0.dist-info}/METADATA +1 -1
  115. klaude_code-2.1.0.dist-info/RECORD +235 -0
  116. klaude_code/cli/runtime.py +0 -518
  117. klaude_code/core/prompt.py +0 -108
  118. klaude_code/core/tool/tool_context.py +0 -148
  119. klaude_code/protocol/events.py +0 -195
  120. klaude_code/skill/assets/dev-docs/SKILL.md +0 -108
  121. klaude_code/trace/__init__.py +0 -21
  122. klaude_code/ui/core/stage_manager.py +0 -48
  123. klaude_code/ui/modes/__init__.py +0 -1
  124. klaude_code/ui/modes/debug/__init__.py +0 -1
  125. klaude_code/ui/modes/exec/__init__.py +0 -1
  126. klaude_code/ui/modes/repl/display.py +0 -61
  127. klaude_code/ui/modes/repl/event_handler.py +0 -629
  128. klaude_code/ui/modes/repl/renderer.py +0 -464
  129. klaude_code/ui/utils/__init__.py +0 -1
  130. klaude_code-2.0.2.dist-info/RECORD +0 -227
  131. /klaude_code/{trace/log.py → log.py} +0 -0
  132. /klaude_code/{command → tui/command}/__init__.py +0 -0
  133. /klaude_code/{command → tui/command}/command_abc.py +0 -0
  134. /klaude_code/{command → tui/command}/prompt-commit.md +0 -0
  135. /klaude_code/{command → tui/command}/prompt-init.md +0 -0
  136. /klaude_code/{ui/renderers → tui/components}/__init__.py +0 -0
  137. /klaude_code/{ui/renderers → tui/components}/mermaid_viewer.py +0 -0
  138. /klaude_code/{ui → tui/components}/rich/__init__.py +0 -0
  139. /klaude_code/{ui → tui/components}/rich/cjk_wrap.py +0 -0
  140. /klaude_code/{ui → tui/components}/rich/code_panel.py +0 -0
  141. /klaude_code/{ui → tui/components}/rich/live.py +0 -0
  142. /klaude_code/{ui → tui/components}/rich/quote.py +0 -0
  143. /klaude_code/{ui → tui/components}/rich/searchable_text.py +0 -0
  144. /klaude_code/{ui/modes/repl → tui/input}/clipboard.py +0 -0
  145. /klaude_code/{ui/modes/repl → tui/input}/key_bindings.py +0 -0
  146. /klaude_code/{ui → tui}/terminal/image.py +0 -0
  147. /klaude_code/{ui → tui}/terminal/progress_bar.py +0 -0
  148. /klaude_code/{ui → tui}/terminal/selector.py +0 -0
  149. /klaude_code/ui/{utils/common.py → common.py} +0 -0
  150. {klaude_code-2.0.2.dist-info → klaude_code-2.1.0.dist-info}/WHEEL +0 -0
  151. {klaude_code-2.0.2.dist-info → klaude_code-2.1.0.dist-info}/entry_points.txt +0 -0
@@ -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, 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):
@@ -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
- 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
- )
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.ResponseMetadataEvent(
342
+ yield events.UsageEvent(
300
343
  session_id=session_ctx.session_id,
301
- metadata=metadata,
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
- yield events.TurnToolCallStartEvent(
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
- 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)
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)
@@ -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
@@ -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,23 @@
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"]
22
+ task_metadata: model.TaskMetadata | None = None
23
+ is_last_in_turn: bool = True
@@ -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)