klaude-code 1.9.0__py3-none-any.whl → 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. klaude_code/auth/base.py +2 -6
  2. klaude_code/cli/auth_cmd.py +4 -4
  3. klaude_code/cli/list_model.py +1 -1
  4. klaude_code/cli/main.py +1 -1
  5. klaude_code/cli/runtime.py +7 -5
  6. klaude_code/cli/self_update.py +1 -1
  7. klaude_code/cli/session_cmd.py +1 -1
  8. klaude_code/command/clear_cmd.py +6 -2
  9. klaude_code/command/command_abc.py +2 -2
  10. klaude_code/command/debug_cmd.py +4 -4
  11. klaude_code/command/export_cmd.py +2 -2
  12. klaude_code/command/export_online_cmd.py +12 -12
  13. klaude_code/command/fork_session_cmd.py +29 -23
  14. klaude_code/command/help_cmd.py +4 -4
  15. klaude_code/command/model_cmd.py +4 -4
  16. klaude_code/command/model_select.py +1 -1
  17. klaude_code/command/prompt-commit.md +11 -2
  18. klaude_code/command/prompt_command.py +3 -3
  19. klaude_code/command/refresh_cmd.py +2 -2
  20. klaude_code/command/registry.py +7 -5
  21. klaude_code/command/release_notes_cmd.py +4 -4
  22. klaude_code/command/resume_cmd.py +15 -11
  23. klaude_code/command/status_cmd.py +4 -4
  24. klaude_code/command/terminal_setup_cmd.py +8 -8
  25. klaude_code/command/thinking_cmd.py +4 -4
  26. klaude_code/config/assets/builtin_config.yaml +16 -0
  27. klaude_code/config/builtin_config.py +16 -5
  28. klaude_code/config/config.py +7 -2
  29. klaude_code/const.py +146 -91
  30. klaude_code/core/agent.py +3 -12
  31. klaude_code/core/executor.py +21 -13
  32. klaude_code/core/manager/sub_agent_manager.py +71 -7
  33. klaude_code/core/prompts/prompt-sub-agent-image-gen.md +1 -0
  34. klaude_code/core/prompts/prompt-sub-agent-web.md +27 -1
  35. klaude_code/core/reminders.py +88 -69
  36. klaude_code/core/task.py +44 -45
  37. klaude_code/core/tool/file/apply_patch_tool.py +9 -9
  38. klaude_code/core/tool/file/diff_builder.py +3 -5
  39. klaude_code/core/tool/file/edit_tool.py +23 -23
  40. klaude_code/core/tool/file/move_tool.py +43 -43
  41. klaude_code/core/tool/file/read_tool.py +44 -39
  42. klaude_code/core/tool/file/write_tool.py +14 -14
  43. klaude_code/core/tool/report_back_tool.py +4 -4
  44. klaude_code/core/tool/shell/bash_tool.py +23 -23
  45. klaude_code/core/tool/skill/skill_tool.py +7 -7
  46. klaude_code/core/tool/sub_agent_tool.py +38 -9
  47. klaude_code/core/tool/todo/todo_write_tool.py +8 -8
  48. klaude_code/core/tool/todo/update_plan_tool.py +6 -6
  49. klaude_code/core/tool/tool_abc.py +2 -2
  50. klaude_code/core/tool/tool_context.py +27 -0
  51. klaude_code/core/tool/tool_runner.py +88 -42
  52. klaude_code/core/tool/truncation.py +38 -20
  53. klaude_code/core/tool/web/mermaid_tool.py +6 -7
  54. klaude_code/core/tool/web/web_fetch_tool.py +68 -30
  55. klaude_code/core/tool/web/web_search_tool.py +15 -17
  56. klaude_code/core/turn.py +120 -73
  57. klaude_code/llm/anthropic/client.py +79 -44
  58. klaude_code/llm/anthropic/input.py +116 -108
  59. klaude_code/llm/bedrock/client.py +8 -5
  60. klaude_code/llm/claude/client.py +18 -8
  61. klaude_code/llm/client.py +4 -3
  62. klaude_code/llm/codex/client.py +15 -9
  63. klaude_code/llm/google/client.py +122 -60
  64. klaude_code/llm/google/input.py +94 -108
  65. klaude_code/llm/image.py +123 -0
  66. klaude_code/llm/input_common.py +136 -189
  67. klaude_code/llm/openai_compatible/client.py +17 -7
  68. klaude_code/llm/openai_compatible/input.py +36 -66
  69. klaude_code/llm/openai_compatible/stream.py +119 -67
  70. klaude_code/llm/openai_compatible/tool_call_accumulator.py +23 -11
  71. klaude_code/llm/openrouter/client.py +34 -9
  72. klaude_code/llm/openrouter/input.py +63 -64
  73. klaude_code/llm/openrouter/reasoning.py +22 -24
  74. klaude_code/llm/registry.py +20 -17
  75. klaude_code/llm/responses/client.py +107 -45
  76. klaude_code/llm/responses/input.py +115 -98
  77. klaude_code/llm/usage.py +52 -25
  78. klaude_code/protocol/__init__.py +1 -0
  79. klaude_code/protocol/events.py +16 -12
  80. klaude_code/protocol/llm_param.py +20 -2
  81. klaude_code/protocol/message.py +250 -0
  82. klaude_code/protocol/model.py +94 -281
  83. klaude_code/protocol/op.py +2 -2
  84. klaude_code/protocol/sub_agent/__init__.py +1 -0
  85. klaude_code/protocol/sub_agent/explore.py +10 -0
  86. klaude_code/protocol/sub_agent/image_gen.py +119 -0
  87. klaude_code/protocol/sub_agent/task.py +10 -0
  88. klaude_code/protocol/sub_agent/web.py +10 -0
  89. klaude_code/session/codec.py +6 -6
  90. klaude_code/session/export.py +261 -62
  91. klaude_code/session/selector.py +7 -24
  92. klaude_code/session/session.py +126 -54
  93. klaude_code/session/store.py +5 -32
  94. klaude_code/session/templates/export_session.html +1 -1
  95. klaude_code/session/templates/mermaid_viewer.html +1 -1
  96. klaude_code/trace/log.py +11 -6
  97. klaude_code/ui/core/input.py +1 -1
  98. klaude_code/ui/core/stage_manager.py +1 -8
  99. klaude_code/ui/modes/debug/display.py +2 -2
  100. klaude_code/ui/modes/repl/clipboard.py +2 -2
  101. klaude_code/ui/modes/repl/completers.py +18 -10
  102. klaude_code/ui/modes/repl/event_handler.py +136 -127
  103. klaude_code/ui/modes/repl/input_prompt_toolkit.py +1 -1
  104. klaude_code/ui/modes/repl/key_bindings.py +1 -1
  105. klaude_code/ui/modes/repl/renderer.py +107 -15
  106. klaude_code/ui/renderers/assistant.py +2 -2
  107. klaude_code/ui/renderers/common.py +65 -7
  108. klaude_code/ui/renderers/developer.py +7 -6
  109. klaude_code/ui/renderers/diffs.py +11 -11
  110. klaude_code/ui/renderers/mermaid_viewer.py +49 -2
  111. klaude_code/ui/renderers/metadata.py +33 -5
  112. klaude_code/ui/renderers/sub_agent.py +57 -16
  113. klaude_code/ui/renderers/thinking.py +37 -2
  114. klaude_code/ui/renderers/tools.py +180 -165
  115. klaude_code/ui/rich/live.py +3 -1
  116. klaude_code/ui/rich/markdown.py +39 -7
  117. klaude_code/ui/rich/quote.py +76 -1
  118. klaude_code/ui/rich/status.py +14 -8
  119. klaude_code/ui/rich/theme.py +8 -2
  120. klaude_code/ui/terminal/image.py +34 -0
  121. klaude_code/ui/terminal/notifier.py +2 -1
  122. klaude_code/ui/terminal/progress_bar.py +4 -4
  123. klaude_code/ui/terminal/selector.py +22 -4
  124. klaude_code/ui/utils/common.py +11 -2
  125. {klaude_code-1.9.0.dist-info → klaude_code-2.0.0.dist-info}/METADATA +4 -2
  126. klaude_code-2.0.0.dist-info/RECORD +229 -0
  127. klaude_code-1.9.0.dist-info/RECORD +0 -224
  128. {klaude_code-1.9.0.dist-info → klaude_code-2.0.0.dist-info}/WHEEL +0 -0
  129. {klaude_code-1.9.0.dist-info → klaude_code-2.0.0.dist-info}/entry_points.txt +0 -0
@@ -14,11 +14,21 @@ Always spawn multiple search agents in parallel to maximise speed.
14
14
  Structured output:
15
15
  - Provide an `output_format` (JSON Schema) parameter for structured data back from the sub-agent
16
16
  - Example: `output_format={"type": "object", "properties": {"files": {"type": "array", "items": {"type": "string"}, "description": "List of file paths that match the search criteria, e.g. ['src/main.py', 'src/utils/helper.py']"}}, "required": ["files"]}`\
17
+
18
+ - Agents can be resumed using the `resume` parameter by passing the agent ID from a previous invocation. When resumed, the agent
19
+ continues with its full previous context preserved. When NOT resuming, each invocation starts fresh and you should provide a detailed
20
+ task description with all necessary context.
21
+ - When the agent is done, it will return a single message back to you along with its agent ID. You can use this ID to resume the agent
22
+ later if needed for follow-up work.
17
23
  """
18
24
 
19
25
  EXPLORE_PARAMETERS = {
20
26
  "type": "object",
21
27
  "properties": {
28
+ "resume": {
29
+ "type": "string",
30
+ "description": "Optional agent ID to resume from. If provided, the agent will continue from the previous execution transcript.",
31
+ },
22
32
  "description": {
23
33
  "type": "string",
24
34
  "description": "Short (3-5 words) label for the exploration goal",
@@ -0,0 +1,119 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, cast
4
+
5
+ from klaude_code.protocol.sub_agent import SubAgentProfile, register_sub_agent
6
+
7
+ IMAGE_GEN_DESCRIPTION = """\
8
+ Generate one or more images from a text prompt.
9
+
10
+ This tool invokes an Image Gen model to generate images. The generated image paths are automatically \
11
+ returned in the response.
12
+
13
+ Inputs:
14
+ - `prompt`: The main instruction describing the desired image.
15
+ - `image_paths` (optional): Local image file paths to use as references for editing or style guidance.
16
+ - `generation` (optional): Per-call image generation settings (aspect ratio / size).
17
+
18
+ Notes:
19
+ - Provide a short textual description of the generated image(s).
20
+ - Do NOT include base64 image data in text output.
21
+ - When providing multiple input images, describe each image's characteristics and purpose in the prompt, \
22
+ not just "image 1, image 2" - the image model cannot distinguish image order. \
23
+ For example: "Edit the first image (a photo of a cat sitting on a windowsill) to match the style of \
24
+ the second image (Van Gogh's Starry Night painting with swirling blue brushstrokes)."
25
+
26
+ Multi-turn image editing:
27
+ - Use `resume` to continue editing a previously generated image. The agent preserves its full context \
28
+ including the generated image, so you don't need to pass `image_paths` again.
29
+ - Example workflow:
30
+ 1. Call ImageGen with prompt="Generate a watercolor painting of a mountain lake" -> returns agent_id
31
+ 2. Call ImageGen with resume=agent_id, prompt="Add a wooden cabin on the shore" -> edits the previous image
32
+ 3. Call ImageGen with resume=agent_id, prompt="Change to sunset lighting" -> continues editing
33
+
34
+ - Agents can be resumed using the `resume` parameter by passing the agent ID from a previous invocation. When resumed, the agent
35
+ continues with its full previous context preserved. When NOT resuming, each invocation starts fresh and you should provide a detailed
36
+ task description with all necessary context.
37
+ - When the agent is done, it will return a single message back to you along with its agent ID. You can use this ID to resume the agent
38
+ later if needed for follow-up work.
39
+
40
+ """
41
+
42
+
43
+ IMAGE_GEN_PARAMETERS: dict[str, Any] = {
44
+ "type": "object",
45
+ "properties": {
46
+ "resume": {
47
+ "type": "string",
48
+ "description": "Optional agent ID to resume from. If provided, the agent will continue from the previous execution transcript.",
49
+ },
50
+ "description": {
51
+ "type": "string",
52
+ "description": "A short (3-5 word) description of the request.",
53
+ },
54
+ "prompt": {
55
+ "type": "string",
56
+ "description": "Text prompt for image generation.",
57
+ },
58
+ "image_paths": {
59
+ "type": "array",
60
+ "items": {"type": "string"},
61
+ "description": "Optional local image file paths used as references.",
62
+ },
63
+ "generation": {
64
+ "type": "object",
65
+ "description": "Optional per-call image generation settings.",
66
+ "properties": {
67
+ "aspect_ratio": {
68
+ "type": "string",
69
+ "description": "Aspect ratio, e.g. '16:9', '1:1', '9:16'.",
70
+ },
71
+ "image_size": {
72
+ "type": "string",
73
+ "enum": ["1K", "2K", "4K"],
74
+ "description": "Output size for Nano Banana Pro (must use uppercase K).",
75
+ },
76
+ "extra": {
77
+ "type": "object",
78
+ "description": "Provider/model-specific extra parameters (future-proofing).",
79
+ },
80
+ },
81
+ "additionalProperties": False,
82
+ },
83
+ },
84
+ "required": ["prompt"],
85
+ "additionalProperties": False,
86
+ }
87
+
88
+
89
+ def _quote_at_pattern_path(path: str) -> str:
90
+ if any(ch.isspace() for ch in path) or '"' in path:
91
+ escaped = path.replace('"', '\\"')
92
+ return f'@"{escaped}"'
93
+ return f"@{path}"
94
+
95
+
96
+ def _build_image_gen_prompt(args: dict[str, Any]) -> str:
97
+ prompt = str(args.get("prompt") or "").strip()
98
+ image_paths = args.get("image_paths")
99
+
100
+ lines: list[str] = ["Generate images: " + prompt]
101
+ if isinstance(image_paths, list) and image_paths:
102
+ referenced = [str(p) for p in cast(list[object], image_paths) if str(p).strip()]
103
+ if referenced:
104
+ lines.append("\n# Reference images\n" + "\n".join(_quote_at_pattern_path(p) for p in referenced))
105
+
106
+ return "\n".join(lines).strip()
107
+
108
+
109
+ register_sub_agent(
110
+ SubAgentProfile(
111
+ name="ImageGen",
112
+ description=IMAGE_GEN_DESCRIPTION,
113
+ parameters=IMAGE_GEN_PARAMETERS,
114
+ prompt_file="prompts/prompt-sub-agent-image-gen.md",
115
+ tool_set=(),
116
+ prompt_builder=_build_image_gen_prompt,
117
+ active_form="Generating Image",
118
+ )
119
+ )
@@ -24,11 +24,21 @@ Usage notes:
24
24
  Structured output:
25
25
  - Provide an `output_format` (JSON Schema) parameter for structured data back from the agent
26
26
  - Example: `output_format={"type": "object", "properties": {"files": {"type": "array", "items": {"type": "string"}, "description": "List of file paths that match the search criteria, e.g. ['src/main.py', 'src/utils/helper.py']"}}, "required": ["files"]}`\
27
+
28
+ - Agents can be resumed using the `resume` parameter by passing the agent ID from a previous invocation. When resumed, the agent
29
+ continues with its full previous context preserved. When NOT resuming, each invocation starts fresh and you should provide a detailed
30
+ task description with all necessary context.
31
+ - When the agent is done, it will return a single message back to you along with its agent ID. You can use this ID to resume the agent
32
+ later if needed for follow-up work.
27
33
  """
28
34
 
29
35
  TASK_PARAMETERS = {
30
36
  "type": "object",
31
37
  "properties": {
38
+ "resume": {
39
+ "type": "string",
40
+ "description": "Optional agent ID to resume from. If provided, the agent will continue from the previous execution transcript.",
41
+ },
32
42
  "description": {
33
43
  "type": "string",
34
44
  "description": "A short (3-5 word) description of the task",
@@ -29,11 +29,21 @@ What you receive:
29
29
  - With `output_format`, you receive structured JSON matching your schema
30
30
  - The response is the agent's analysis, not raw web content
31
31
  - Web content is saved to local files (paths included in Sources) - read them directly if you need full content\
32
+
33
+ - Agents can be resumed using the `resume` parameter by passing the agent ID from a previous invocation. When resumed, the agent
34
+ continues with its full previous context preserved. When NOT resuming, each invocation starts fresh and you should provide a detailed
35
+ task description with all necessary context.
36
+ - When the agent is done, it will return a single message back to you along with its agent ID. You can use this ID to resume the agent
37
+ later if needed for follow-up work.
32
38
  """
33
39
 
34
40
  WEB_AGENT_PARAMETERS = {
35
41
  "type": "object",
36
42
  "properties": {
43
+ "resume": {
44
+ "type": "string",
45
+ "description": "Optional agent ID to resume from. If provided, the agent will continue from the previous execution transcript.",
46
+ },
37
47
  "description": {
38
48
  "type": "string",
39
49
  "description": "A short (3-5 word) description of the task",
@@ -5,7 +5,7 @@ from typing import Any, TypeGuard, cast, get_args
5
5
 
6
6
  from pydantic import BaseModel
7
7
 
8
- from klaude_code.protocol import model
8
+ from klaude_code.protocol import message
9
9
 
10
10
 
11
11
  def _is_basemodel_subclass(tp: object) -> TypeGuard[type[BaseModel]]:
@@ -24,7 +24,7 @@ def _flatten_union(tp: object) -> list[object]:
24
24
 
25
25
  def _build_type_registry() -> dict[str, type[BaseModel]]:
26
26
  registry: dict[str, type[BaseModel]] = {}
27
- for tp in _flatten_union(model.ConversationItem):
27
+ for tp in _flatten_union(message.HistoryEvent):
28
28
  if not _is_basemodel_subclass(tp):
29
29
  continue
30
30
  registry[tp.__name__] = tp
@@ -34,11 +34,11 @@ def _build_type_registry() -> dict[str, type[BaseModel]]:
34
34
  _CONVERSATION_ITEM_TYPES: dict[str, type[BaseModel]] = _build_type_registry()
35
35
 
36
36
 
37
- def encode_conversation_item(item: model.ConversationItem) -> dict[str, Any]:
37
+ def encode_conversation_item(item: message.HistoryEvent) -> dict[str, Any]:
38
38
  return {"type": item.__class__.__name__, "data": item.model_dump(mode="json")}
39
39
 
40
40
 
41
- def decode_conversation_item(obj: dict[str, Any]) -> model.ConversationItem | None:
41
+ def decode_conversation_item(obj: dict[str, Any]) -> message.HistoryEvent | None:
42
42
  t = obj.get("type")
43
43
  data = obj.get("data", {})
44
44
  if not isinstance(t, str) or not isinstance(data, dict):
@@ -54,11 +54,11 @@ def decode_conversation_item(obj: dict[str, Any]) -> model.ConversationItem | No
54
54
  return item # type: ignore[return-value]
55
55
 
56
56
 
57
- def encode_jsonl_line(item: model.ConversationItem) -> str:
57
+ def encode_jsonl_line(item: message.HistoryEvent) -> str:
58
58
  return json.dumps(encode_conversation_item(item), ensure_ascii=False) + "\n"
59
59
 
60
60
 
61
- def decode_jsonl_line(line: str) -> model.ConversationItem | None:
61
+ def decode_jsonl_line(line: str) -> message.HistoryEvent | None:
62
62
  line = line.strip()
63
63
  if not line:
64
64
  return None