klaude-code 1.2.6__py3-none-any.whl → 1.8.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 (205) hide show
  1. klaude_code/auth/__init__.py +24 -0
  2. klaude_code/auth/codex/__init__.py +20 -0
  3. klaude_code/auth/codex/exceptions.py +17 -0
  4. klaude_code/auth/codex/jwt_utils.py +45 -0
  5. klaude_code/auth/codex/oauth.py +229 -0
  6. klaude_code/auth/codex/token_manager.py +84 -0
  7. klaude_code/cli/auth_cmd.py +73 -0
  8. klaude_code/cli/config_cmd.py +91 -0
  9. klaude_code/cli/cost_cmd.py +338 -0
  10. klaude_code/cli/debug.py +78 -0
  11. klaude_code/cli/list_model.py +307 -0
  12. klaude_code/cli/main.py +233 -134
  13. klaude_code/cli/runtime.py +309 -117
  14. klaude_code/{version.py → cli/self_update.py} +114 -5
  15. klaude_code/cli/session_cmd.py +37 -21
  16. klaude_code/command/__init__.py +88 -27
  17. klaude_code/command/clear_cmd.py +8 -7
  18. klaude_code/command/command_abc.py +31 -31
  19. klaude_code/command/debug_cmd.py +79 -0
  20. klaude_code/command/export_cmd.py +19 -53
  21. klaude_code/command/export_online_cmd.py +154 -0
  22. klaude_code/command/fork_session_cmd.py +267 -0
  23. klaude_code/command/help_cmd.py +7 -8
  24. klaude_code/command/model_cmd.py +60 -10
  25. klaude_code/command/model_select.py +84 -0
  26. klaude_code/command/prompt-jj-describe.md +32 -0
  27. klaude_code/command/prompt_command.py +19 -11
  28. klaude_code/command/refresh_cmd.py +8 -10
  29. klaude_code/command/registry.py +139 -40
  30. klaude_code/command/release_notes_cmd.py +84 -0
  31. klaude_code/command/resume_cmd.py +111 -0
  32. klaude_code/command/status_cmd.py +104 -60
  33. klaude_code/command/terminal_setup_cmd.py +7 -9
  34. klaude_code/command/thinking_cmd.py +98 -0
  35. klaude_code/config/__init__.py +14 -6
  36. klaude_code/config/assets/__init__.py +1 -0
  37. klaude_code/config/assets/builtin_config.yaml +303 -0
  38. klaude_code/config/builtin_config.py +38 -0
  39. klaude_code/config/config.py +378 -109
  40. klaude_code/config/select_model.py +117 -53
  41. klaude_code/config/thinking.py +269 -0
  42. klaude_code/{const/__init__.py → const.py} +50 -19
  43. klaude_code/core/agent.py +20 -28
  44. klaude_code/core/executor.py +327 -112
  45. klaude_code/core/manager/__init__.py +2 -4
  46. klaude_code/core/manager/llm_clients.py +1 -15
  47. klaude_code/core/manager/llm_clients_builder.py +10 -11
  48. klaude_code/core/manager/sub_agent_manager.py +37 -6
  49. klaude_code/core/prompt.py +63 -44
  50. klaude_code/core/prompts/prompt-claude-code.md +2 -13
  51. klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +117 -0
  52. klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +117 -0
  53. klaude_code/core/prompts/prompt-codex.md +9 -42
  54. klaude_code/core/prompts/prompt-minimal.md +12 -0
  55. klaude_code/core/prompts/{prompt-subagent-explore.md → prompt-sub-agent-explore.md} +16 -3
  56. klaude_code/core/prompts/{prompt-subagent-oracle.md → prompt-sub-agent-oracle.md} +1 -2
  57. klaude_code/core/prompts/prompt-sub-agent-web.md +51 -0
  58. klaude_code/core/reminders.py +283 -95
  59. klaude_code/core/task.py +113 -75
  60. klaude_code/core/tool/__init__.py +24 -31
  61. klaude_code/core/tool/file/_utils.py +36 -0
  62. klaude_code/core/tool/file/apply_patch.py +17 -25
  63. klaude_code/core/tool/file/apply_patch_tool.py +57 -77
  64. klaude_code/core/tool/file/diff_builder.py +151 -0
  65. klaude_code/core/tool/file/edit_tool.py +50 -63
  66. klaude_code/core/tool/file/move_tool.md +41 -0
  67. klaude_code/core/tool/file/move_tool.py +435 -0
  68. klaude_code/core/tool/file/read_tool.md +1 -1
  69. klaude_code/core/tool/file/read_tool.py +86 -86
  70. klaude_code/core/tool/file/write_tool.py +59 -69
  71. klaude_code/core/tool/report_back_tool.py +84 -0
  72. klaude_code/core/tool/shell/bash_tool.py +265 -22
  73. klaude_code/core/tool/shell/command_safety.py +3 -6
  74. klaude_code/core/tool/{memory → skill}/skill_tool.py +16 -26
  75. klaude_code/core/tool/sub_agent_tool.py +13 -2
  76. klaude_code/core/tool/todo/todo_write_tool.md +0 -157
  77. klaude_code/core/tool/todo/todo_write_tool.py +1 -1
  78. klaude_code/core/tool/todo/todo_write_tool_raw.md +182 -0
  79. klaude_code/core/tool/todo/update_plan_tool.py +1 -1
  80. klaude_code/core/tool/tool_abc.py +18 -0
  81. klaude_code/core/tool/tool_context.py +27 -12
  82. klaude_code/core/tool/tool_registry.py +7 -7
  83. klaude_code/core/tool/tool_runner.py +44 -36
  84. klaude_code/core/tool/truncation.py +29 -14
  85. klaude_code/core/tool/web/mermaid_tool.md +43 -0
  86. klaude_code/core/tool/web/mermaid_tool.py +2 -5
  87. klaude_code/core/tool/web/web_fetch_tool.md +1 -1
  88. klaude_code/core/tool/web/web_fetch_tool.py +112 -22
  89. klaude_code/core/tool/web/web_search_tool.md +23 -0
  90. klaude_code/core/tool/web/web_search_tool.py +130 -0
  91. klaude_code/core/turn.py +168 -66
  92. klaude_code/llm/__init__.py +2 -10
  93. klaude_code/llm/anthropic/client.py +190 -178
  94. klaude_code/llm/anthropic/input.py +39 -15
  95. klaude_code/llm/bedrock/__init__.py +3 -0
  96. klaude_code/llm/bedrock/client.py +60 -0
  97. klaude_code/llm/client.py +7 -21
  98. klaude_code/llm/codex/__init__.py +5 -0
  99. klaude_code/llm/codex/client.py +149 -0
  100. klaude_code/llm/google/__init__.py +3 -0
  101. klaude_code/llm/google/client.py +309 -0
  102. klaude_code/llm/google/input.py +215 -0
  103. klaude_code/llm/input_common.py +3 -9
  104. klaude_code/llm/openai_compatible/client.py +72 -164
  105. klaude_code/llm/openai_compatible/input.py +6 -4
  106. klaude_code/llm/openai_compatible/stream.py +273 -0
  107. klaude_code/llm/openai_compatible/tool_call_accumulator.py +17 -1
  108. klaude_code/llm/openrouter/client.py +89 -160
  109. klaude_code/llm/openrouter/input.py +18 -30
  110. klaude_code/llm/openrouter/reasoning.py +118 -0
  111. klaude_code/llm/registry.py +39 -7
  112. klaude_code/llm/responses/client.py +184 -171
  113. klaude_code/llm/responses/input.py +20 -1
  114. klaude_code/llm/usage.py +17 -12
  115. klaude_code/protocol/commands.py +17 -1
  116. klaude_code/protocol/events.py +31 -4
  117. klaude_code/protocol/llm_param.py +13 -10
  118. klaude_code/protocol/model.py +232 -29
  119. klaude_code/protocol/op.py +90 -1
  120. klaude_code/protocol/op_handler.py +35 -1
  121. klaude_code/protocol/sub_agent/__init__.py +117 -0
  122. klaude_code/protocol/sub_agent/explore.py +63 -0
  123. klaude_code/protocol/sub_agent/oracle.py +91 -0
  124. klaude_code/protocol/sub_agent/task.py +61 -0
  125. klaude_code/protocol/sub_agent/web.py +79 -0
  126. klaude_code/protocol/tools.py +4 -2
  127. klaude_code/session/__init__.py +2 -2
  128. klaude_code/session/codec.py +71 -0
  129. klaude_code/session/export.py +293 -86
  130. klaude_code/session/selector.py +89 -67
  131. klaude_code/session/session.py +320 -309
  132. klaude_code/session/store.py +220 -0
  133. klaude_code/session/templates/export_session.html +595 -83
  134. klaude_code/session/templates/mermaid_viewer.html +926 -0
  135. klaude_code/skill/__init__.py +27 -0
  136. klaude_code/skill/assets/deslop/SKILL.md +17 -0
  137. klaude_code/skill/assets/dev-docs/SKILL.md +108 -0
  138. klaude_code/skill/assets/handoff/SKILL.md +39 -0
  139. klaude_code/skill/assets/jj-workspace/SKILL.md +20 -0
  140. klaude_code/skill/assets/skill-creator/SKILL.md +139 -0
  141. klaude_code/{core/tool/memory/skill_loader.py → skill/loader.py} +55 -15
  142. klaude_code/skill/manager.py +70 -0
  143. klaude_code/skill/system_skills.py +192 -0
  144. klaude_code/trace/__init__.py +20 -2
  145. klaude_code/trace/log.py +150 -5
  146. klaude_code/ui/__init__.py +4 -9
  147. klaude_code/ui/core/input.py +1 -1
  148. klaude_code/ui/core/stage_manager.py +7 -7
  149. klaude_code/ui/modes/debug/display.py +2 -1
  150. klaude_code/ui/modes/repl/__init__.py +3 -48
  151. klaude_code/ui/modes/repl/clipboard.py +5 -5
  152. klaude_code/ui/modes/repl/completers.py +487 -123
  153. klaude_code/ui/modes/repl/display.py +5 -4
  154. klaude_code/ui/modes/repl/event_handler.py +370 -117
  155. klaude_code/ui/modes/repl/input_prompt_toolkit.py +552 -105
  156. klaude_code/ui/modes/repl/key_bindings.py +146 -23
  157. klaude_code/ui/modes/repl/renderer.py +189 -99
  158. klaude_code/ui/renderers/assistant.py +9 -2
  159. klaude_code/ui/renderers/bash_syntax.py +178 -0
  160. klaude_code/ui/renderers/common.py +78 -0
  161. klaude_code/ui/renderers/developer.py +104 -48
  162. klaude_code/ui/renderers/diffs.py +87 -6
  163. klaude_code/ui/renderers/errors.py +11 -6
  164. klaude_code/ui/renderers/mermaid_viewer.py +57 -0
  165. klaude_code/ui/renderers/metadata.py +112 -76
  166. klaude_code/ui/renderers/sub_agent.py +92 -7
  167. klaude_code/ui/renderers/thinking.py +40 -18
  168. klaude_code/ui/renderers/tools.py +405 -227
  169. klaude_code/ui/renderers/user_input.py +73 -13
  170. klaude_code/ui/rich/__init__.py +10 -1
  171. klaude_code/ui/rich/cjk_wrap.py +228 -0
  172. klaude_code/ui/rich/code_panel.py +131 -0
  173. klaude_code/ui/rich/live.py +17 -0
  174. klaude_code/ui/rich/markdown.py +305 -170
  175. klaude_code/ui/rich/searchable_text.py +10 -13
  176. klaude_code/ui/rich/status.py +190 -49
  177. klaude_code/ui/rich/theme.py +135 -39
  178. klaude_code/ui/terminal/__init__.py +55 -0
  179. klaude_code/ui/terminal/color.py +1 -1
  180. klaude_code/ui/terminal/control.py +13 -22
  181. klaude_code/ui/terminal/notifier.py +44 -4
  182. klaude_code/ui/terminal/selector.py +658 -0
  183. klaude_code/ui/utils/common.py +0 -18
  184. klaude_code-1.8.0.dist-info/METADATA +377 -0
  185. klaude_code-1.8.0.dist-info/RECORD +219 -0
  186. {klaude_code-1.2.6.dist-info → klaude_code-1.8.0.dist-info}/entry_points.txt +1 -0
  187. klaude_code/command/diff_cmd.py +0 -138
  188. klaude_code/command/prompt-dev-docs-update.md +0 -56
  189. klaude_code/command/prompt-dev-docs.md +0 -46
  190. klaude_code/config/list_model.py +0 -162
  191. klaude_code/core/manager/agent_manager.py +0 -127
  192. klaude_code/core/prompts/prompt-subagent-webfetch.md +0 -46
  193. klaude_code/core/tool/file/multi_edit_tool.md +0 -42
  194. klaude_code/core/tool/file/multi_edit_tool.py +0 -199
  195. klaude_code/core/tool/memory/memory_tool.md +0 -16
  196. klaude_code/core/tool/memory/memory_tool.py +0 -462
  197. klaude_code/llm/openrouter/reasoning_handler.py +0 -209
  198. klaude_code/protocol/sub_agent.py +0 -348
  199. klaude_code/ui/utils/debouncer.py +0 -42
  200. klaude_code-1.2.6.dist-info/METADATA +0 -178
  201. klaude_code-1.2.6.dist-info/RECORD +0 -167
  202. /klaude_code/core/prompts/{prompt-subagent.md → prompt-sub-agent.md} +0 -0
  203. /klaude_code/core/tool/{memory → skill}/__init__.py +0 -0
  204. /klaude_code/core/tool/{memory → skill}/skill_tool.md +0 -0
  205. {klaude_code-1.2.6.dist-info → klaude_code-1.8.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,117 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable
4
+ from dataclasses import dataclass, field
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from klaude_code.protocol import tools
8
+
9
+ if TYPE_CHECKING:
10
+ from klaude_code.protocol import model
11
+
12
+ AvailabilityPredicate = Callable[[str], bool]
13
+ PromptBuilder = Callable[[dict[str, Any]], str]
14
+
15
+
16
+ @dataclass
17
+ class SubAgentResult:
18
+ task_result: str
19
+ session_id: str
20
+ error: bool = False
21
+ task_metadata: model.TaskMetadata | None = None
22
+
23
+
24
+ def _default_prompt_builder(args: dict[str, Any]) -> str:
25
+ """Default prompt builder that just returns the 'prompt' field."""
26
+ return args.get("prompt", "")
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class SubAgentProfile:
31
+ """Metadata describing a sub agent and how it integrates with the system.
32
+
33
+ This dataclass contains all the information needed to:
34
+ 1. Register the sub agent with the system
35
+ 2. Generate the tool schema for the main agent
36
+ 3. Build the prompt for the sub agent
37
+ """
38
+
39
+ # Identity - single name used for type, tool_name, config_key, and prompt_key
40
+ name: str # e.g., "Task", "Oracle", "Explore"
41
+
42
+ # Tool schema
43
+ description: str # Tool description shown to the main agent
44
+ parameters: dict[str, Any] = field(
45
+ default_factory=lambda: dict[str, Any](), hash=False
46
+ ) # JSON Schema for tool parameters
47
+
48
+ # System prompt
49
+ prompt_file: str = "" # Resource file path relative to core package (e.g., "prompts/prompt-sub-agent.md")
50
+
51
+ # Sub agent configuration
52
+ tool_set: tuple[str, ...] = () # Tools available to this sub agent
53
+ prompt_builder: PromptBuilder = _default_prompt_builder # Builds the sub agent prompt from tool arguments
54
+
55
+ # UI display
56
+ active_form: str = "" # Active form for spinner status (e.g., "Tasking", "Exploring")
57
+
58
+ # Availability
59
+ enabled_by_default: bool = True
60
+ show_in_main_agent: bool = True
61
+ target_model_filter: AvailabilityPredicate | None = None
62
+
63
+ # Structured output support: specifies which parameter in the tool schema contains the output schema
64
+ output_schema_arg: str | None = None
65
+
66
+ def enabled_for_model(self, model_name: str | None) -> bool:
67
+ if not self.enabled_by_default:
68
+ return False
69
+ if model_name is None or self.target_model_filter is None:
70
+ return True
71
+ return self.target_model_filter(model_name)
72
+
73
+
74
+ _PROFILES: dict[str, SubAgentProfile] = {}
75
+
76
+
77
+ def register_sub_agent(profile: SubAgentProfile) -> None:
78
+ if profile.name in _PROFILES:
79
+ raise ValueError(f"Duplicate sub agent profile: {profile.name}")
80
+ _PROFILES[profile.name] = profile
81
+
82
+
83
+ def get_sub_agent_profile(sub_agent_type: tools.SubAgentType) -> SubAgentProfile:
84
+ try:
85
+ return _PROFILES[sub_agent_type]
86
+ except KeyError as exc:
87
+ raise KeyError(f"Unknown sub agent type: {sub_agent_type}") from exc
88
+
89
+
90
+ def iter_sub_agent_profiles(enabled_only: bool = False, model_name: str | None = None) -> list[SubAgentProfile]:
91
+ profiles = list(_PROFILES.values())
92
+ if not enabled_only:
93
+ return profiles
94
+ return [p for p in profiles if p.enabled_for_model(model_name)]
95
+
96
+
97
+ def get_sub_agent_profile_by_tool(tool_name: str) -> SubAgentProfile | None:
98
+ return _PROFILES.get(tool_name)
99
+
100
+
101
+ def is_sub_agent_tool(tool_name: str) -> bool:
102
+ return tool_name in _PROFILES
103
+
104
+
105
+ def sub_agent_tool_names(enabled_only: bool = False, model_name: str | None = None) -> list[str]:
106
+ return [
107
+ profile.name
108
+ for profile in iter_sub_agent_profiles(enabled_only=enabled_only, model_name=model_name)
109
+ if profile.show_in_main_agent
110
+ ]
111
+
112
+
113
+ # Import sub-agent modules to trigger registration
114
+ from klaude_code.protocol.sub_agent import explore as explore # noqa: E402
115
+ from klaude_code.protocol.sub_agent import oracle as oracle # noqa: E402
116
+ from klaude_code.protocol.sub_agent import task as task # noqa: E402
117
+ from klaude_code.protocol.sub_agent import web as web # noqa: E402
@@ -0,0 +1,63 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from klaude_code.protocol import tools
6
+ from klaude_code.protocol.sub_agent import SubAgentProfile, register_sub_agent
7
+
8
+ EXPLORE_DESCRIPTION = """\
9
+ Spin up a fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), \
10
+ search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?")\
11
+ When calling this agent, specify the desired thoroughness level: "quick" for basic searches, "medium" for moderate exploration, or "very thorough" for comprehensive analysis across multiple locations and naming conventions.
12
+ Always spawn multiple search agents in parallel to maximise speed.
13
+
14
+ Structured output:
15
+ - Provide an `output_format` (JSON Schema) parameter for structured data back from the sub-agent
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
+
19
+ EXPLORE_PARAMETERS = {
20
+ "type": "object",
21
+ "properties": {
22
+ "description": {
23
+ "type": "string",
24
+ "description": "Short (3-5 words) label for the exploration goal",
25
+ },
26
+ "prompt": {
27
+ "type": "string",
28
+ "description": "The task for the agent to perform",
29
+ },
30
+ "thoroughness": {
31
+ "type": "string",
32
+ "enum": ["quick", "medium", "very thorough"],
33
+ "description": "Controls how deep the sub-agent should search the repo",
34
+ },
35
+ "output_format": {
36
+ "type": "object",
37
+ "description": "Optional JSON Schema for sub-agent structured output",
38
+ },
39
+ },
40
+ "required": ["description", "prompt"],
41
+ "additionalProperties": False,
42
+ }
43
+
44
+
45
+ def _explore_prompt_builder(args: dict[str, Any]) -> str:
46
+ """Build the Explore prompt from tool arguments."""
47
+ prompt = args.get("prompt", "").strip()
48
+ thoroughness = args.get("thoroughness", "medium")
49
+ return f"{prompt}\nthoroughness: {thoroughness}"
50
+
51
+
52
+ register_sub_agent(
53
+ SubAgentProfile(
54
+ name="Explore",
55
+ description=EXPLORE_DESCRIPTION,
56
+ parameters=EXPLORE_PARAMETERS,
57
+ prompt_file="prompts/prompt-sub-agent-explore.md",
58
+ tool_set=(tools.BASH, tools.READ),
59
+ prompt_builder=_explore_prompt_builder,
60
+ active_form="Exploring",
61
+ output_schema_arg="output_format",
62
+ )
63
+ )
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from klaude_code.protocol import tools
6
+ from klaude_code.protocol.sub_agent import SubAgentProfile, register_sub_agent
7
+
8
+ ORACLE_DESCRIPTION = """\
9
+ Consult the Oracle - an AI advisor powered by OpenAI's premium reasoning model that can plan, review, and provide expert guidance.
10
+
11
+ The Oracle has access to the following tools: Read, Bash.
12
+
13
+ The Oracle acts as your senior engineering advisor and can help with:
14
+
15
+ WHEN TO USE THE ORACLE:
16
+ - Code reviews and architecture feedback
17
+ - Finding a bug in multiple files
18
+ - Planning complex implementations or refactoring
19
+ - Analyzing code quality and suggesting improvements
20
+ - Answering complex technical questions that require deep reasoning
21
+
22
+ WHEN NOT TO USE THE ORACLE:
23
+ - Simple file reading or searching tasks (use Read or Grep directly)
24
+ - Codebase searches (use Task)
25
+ - Basic code modifications and when you need to execute code changes (do it yourself or use Task)
26
+
27
+ USAGE GUIDELINES:
28
+ 1. Be specific about what you want the Oracle to review, plan, or debug
29
+ 2. Provide relevant context about what you're trying to achieve. If you know that any files are involved, list them and they will be attached.
30
+
31
+
32
+ EXAMPLES:
33
+ - "Review the authentication system architecture and suggest improvements"
34
+ - "Plan the implementation of real-time collaboration features"
35
+ - "Analyze the performance bottlenecks in the data processing pipeline"
36
+ - "Review this API design and suggest better patterns"\
37
+ """
38
+
39
+ ORACLE_PARAMETERS = {
40
+ "properties": {
41
+ "context": {
42
+ "description": "Optional context about the current situation, what you've tried, or background information that would help the Oracle provide better guidance.",
43
+ "type": "string",
44
+ },
45
+ "files": {
46
+ "description": "Optional list of specific file paths (text files, images) that the Oracle should examine as part of its analysis. These files will be attached to the Oracle input.",
47
+ "items": {"type": "string"},
48
+ "type": "array",
49
+ },
50
+ "task": {
51
+ "description": "The task or question you want the Oracle to help with. Be specific about what kind of guidance, review, or planning you need.",
52
+ "type": "string",
53
+ },
54
+ "description": {
55
+ "description": "A short (3-5 word) description of the task",
56
+ "type": "string",
57
+ },
58
+ },
59
+ "required": ["task", "description"],
60
+ "type": "object",
61
+ }
62
+
63
+
64
+ def _oracle_prompt_builder(args: dict[str, Any]) -> str:
65
+ """Build the Oracle prompt from tool arguments."""
66
+ context = args.get("context", "")
67
+ task = args.get("task", "")
68
+ files = args.get("files", [])
69
+
70
+ prompt = f"""\
71
+ Context: {context}
72
+ Task: {task}\
73
+ """
74
+ if files:
75
+ files_str = "\n".join(f"@{file}" for file in files)
76
+ prompt += f"\nRelated files to review:\n{files_str}"
77
+ return prompt
78
+
79
+
80
+ register_sub_agent(
81
+ SubAgentProfile(
82
+ name="Oracle",
83
+ description=ORACLE_DESCRIPTION,
84
+ parameters=ORACLE_PARAMETERS,
85
+ prompt_file="prompts/prompt-sub-agent-oracle.md",
86
+ tool_set=(tools.READ, tools.BASH),
87
+ prompt_builder=_oracle_prompt_builder,
88
+ active_form="Consulting Oracle",
89
+ target_model_filter=lambda model: ("gpt-5" not in model) and ("gemini-3" not in model),
90
+ )
91
+ )
@@ -0,0 +1,61 @@
1
+ from __future__ import annotations
2
+
3
+ from klaude_code.protocol import tools
4
+ from klaude_code.protocol.sub_agent import SubAgentProfile, register_sub_agent
5
+
6
+ TASK_DESCRIPTION = """\
7
+ Launch a new agent to handle complex, multi-step tasks autonomously. \
8
+
9
+ When NOT to use the Task tool:
10
+ - If you want to read a specific file path, use the Read or Bash tool for `rg` instead of the Task tool, to find the match more quickly
11
+ - If you are searching for a specific class definition like "class Foo", use the Bash tool for `rg` instead, to find the match more quickly
12
+ - If you are searching for code within a specific file or set of 2-3 files, use the Read tool instead of the Task tool, to find the match more quickly
13
+ - Other tasks that are not related to the agent descriptions above
14
+
15
+ Usage notes:
16
+ - Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
17
+ - When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.
18
+ - Each agent invocation is stateless. You will not be able to send additional messages to the agent, nor will the agent be able to communicate with you outside of its final report. Therefore, your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what information the agent should return back to you in its final and only message to you.
19
+ - The agent's outputs should generally be trusted
20
+ - Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, etc.), since it is not aware of the user's intent
21
+ - If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.
22
+ - If the user specifies that they want you to run agents "in parallel", you MUST send a single message with multiple Task tool use content blocks. For example, if you need to launch both a code-reviewer agent and a test-runner agent in parallel, send a single message with both tool calls.
23
+
24
+ Structured output:
25
+ - Provide an `output_format` (JSON Schema) parameter for structured data back from the agent
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
+
29
+ TASK_PARAMETERS = {
30
+ "type": "object",
31
+ "properties": {
32
+ "description": {
33
+ "type": "string",
34
+ "description": "A short (3-5 word) description of the task",
35
+ },
36
+ "prompt": {
37
+ "type": "string",
38
+ "description": "The task for the agent to perform",
39
+ },
40
+ "output_format": {
41
+ "type": "object",
42
+ "description": (
43
+ "Optional JSON Schema for structured output, better with examples in argument descriptions."
44
+ ),
45
+ },
46
+ },
47
+ "required": ["description", "prompt"],
48
+ "additionalProperties": False,
49
+ }
50
+
51
+ register_sub_agent(
52
+ SubAgentProfile(
53
+ name="Task",
54
+ description=TASK_DESCRIPTION,
55
+ parameters=TASK_PARAMETERS,
56
+ prompt_file="prompts/prompt-sub-agent.md",
57
+ tool_set=(tools.BASH, tools.READ, tools.EDIT, tools.WRITE, tools.MOVE),
58
+ active_form="Tasking",
59
+ output_schema_arg="output_format",
60
+ )
61
+ )
@@ -0,0 +1,79 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from klaude_code.protocol import tools
6
+ from klaude_code.protocol.sub_agent import SubAgentProfile, register_sub_agent
7
+
8
+ WEB_AGENT_DESCRIPTION = """\
9
+ Launch a sub-agent to search the web, fetch pages, and analyze content. Use this for:
10
+ - Accessing up-to-date information beyond your knowledge cutoff (current events, recent releases, latest docs)
11
+ - Researching topics, news, APIs, or technical references
12
+ - Fetching and analyzing specific URLs
13
+ - Gathering comprehensive information from multiple web sources
14
+
15
+ Capabilities:
16
+ - Search the web to find relevant pages (no URL required)
17
+ - Fetch and parse web pages (HTML-to-Markdown conversion)
18
+ - Follow links across multiple pages autonomously
19
+ - Aggregate findings from multiple sources
20
+
21
+ How to use:
22
+ - Write a clear prompt describing what information you need - the agent will search and fetch as needed
23
+ - Account for "Today's date" in <env>. For example, if <env> says "Today's date: 2025-07-01", and the user wants the latest docs, do not use 2024 in the search query. Use 2025.
24
+ - Optionally provide a `url` if you already know the target page
25
+ - Use `output_format` (JSON Schema) to get structured data back from the agent
26
+
27
+ What you receive:
28
+ - The agent returns a text response summarizing its findings
29
+ - With `output_format`, you receive structured JSON matching your schema
30
+ - The response is the agent's analysis, not raw web content
31
+ - Web content is saved to local files (paths included in Sources) - read them directly if you need full content\
32
+ """
33
+
34
+ WEB_AGENT_PARAMETERS = {
35
+ "type": "object",
36
+ "properties": {
37
+ "description": {
38
+ "type": "string",
39
+ "description": "A short (3-5 word) description of the task",
40
+ },
41
+ "url": {
42
+ "type": "string",
43
+ "description": "The URL to fetch and analyze. If not provided, the agent will search the web first",
44
+ },
45
+ "prompt": {
46
+ "type": "string",
47
+ "description": "Instructions for searching, analyzing, or extracting content from the web page",
48
+ },
49
+ "output_format": {
50
+ "type": "object",
51
+ "description": "Optional JSON Schema for sub-agent structured output",
52
+ },
53
+ },
54
+ "required": ["description", "prompt"],
55
+ "additionalProperties": False,
56
+ }
57
+
58
+
59
+ def _web_agent_prompt_builder(args: dict[str, Any]) -> str:
60
+ """Build the WebAgent prompt from tool arguments."""
61
+ url = args.get("url", "")
62
+ prompt = args.get("prompt", "")
63
+ if url:
64
+ return f"URL to fetch: {url}\nTask: {prompt}"
65
+ return prompt
66
+
67
+
68
+ register_sub_agent(
69
+ SubAgentProfile(
70
+ name="WebAgent",
71
+ description=WEB_AGENT_DESCRIPTION,
72
+ parameters=WEB_AGENT_PARAMETERS,
73
+ prompt_file="prompts/prompt-sub-agent-web.md",
74
+ tool_set=(tools.BASH, tools.READ, tools.WEB_FETCH, tools.WEB_SEARCH, tools.WRITE),
75
+ prompt_builder=_web_agent_prompt_builder,
76
+ active_form="Surfing",
77
+ output_schema_arg="output_format",
78
+ )
79
+ )
@@ -1,15 +1,17 @@
1
1
  BASH = "Bash"
2
2
  APPLY_PATCH = "apply_patch"
3
+ MOVE = "Move"
3
4
  EDIT = "Edit"
4
- MULTI_EDIT = "MultiEdit"
5
+
5
6
  READ = "Read"
6
7
  WRITE = "Write"
7
8
  TODO_WRITE = "TodoWrite"
8
9
  UPDATE_PLAN = "update_plan"
9
10
  SKILL = "Skill"
10
11
  MERMAID = "Mermaid"
11
- MEMORY = "Memory"
12
12
  WEB_FETCH = "WebFetch"
13
+ WEB_SEARCH = "WebSearch"
14
+ REPORT_BACK = "report_back"
13
15
 
14
16
  # SubAgentType is just a string alias now; agent types are defined via SubAgentProfile
15
17
  SubAgentType = str
@@ -1,4 +1,4 @@
1
- from .selector import resume_select_session
1
+ from .selector import SessionSelectOption, build_session_select_options, format_user_messages_display
2
2
  from .session import Session
3
3
 
4
- __all__ = ["Session", "resume_select_session"]
4
+ __all__ = ["Session", "SessionSelectOption", "build_session_select_options", "format_user_messages_display"]
@@ -0,0 +1,71 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from typing import Any, TypeGuard, cast, get_args
5
+
6
+ from pydantic import BaseModel
7
+
8
+ from klaude_code.protocol import model
9
+
10
+
11
+ def _is_basemodel_subclass(tp: object) -> TypeGuard[type[BaseModel]]:
12
+ return isinstance(tp, type) and issubclass(tp, BaseModel)
13
+
14
+
15
+ def _flatten_union(tp: object) -> list[object]:
16
+ args = list(get_args(tp))
17
+ if not args:
18
+ return [tp]
19
+ flattened: list[object] = []
20
+ for arg in args:
21
+ flattened.extend(_flatten_union(arg))
22
+ return flattened
23
+
24
+
25
+ def _build_type_registry() -> dict[str, type[BaseModel]]:
26
+ registry: dict[str, type[BaseModel]] = {}
27
+ for tp in _flatten_union(model.ConversationItem):
28
+ if not _is_basemodel_subclass(tp):
29
+ continue
30
+ registry[tp.__name__] = tp
31
+ return registry
32
+
33
+
34
+ _CONVERSATION_ITEM_TYPES: dict[str, type[BaseModel]] = _build_type_registry()
35
+
36
+
37
+ def encode_conversation_item(item: model.ConversationItem) -> dict[str, Any]:
38
+ return {"type": item.__class__.__name__, "data": item.model_dump(mode="json")}
39
+
40
+
41
+ def decode_conversation_item(obj: dict[str, Any]) -> model.ConversationItem | None:
42
+ t = obj.get("type")
43
+ data = obj.get("data", {})
44
+ if not isinstance(t, str) or not isinstance(data, dict):
45
+ return None
46
+ cls = _CONVERSATION_ITEM_TYPES.get(t)
47
+ if cls is None:
48
+ return None
49
+ try:
50
+ item = cls(**data)
51
+ except TypeError:
52
+ return None
53
+ # pyright: ignore[reportReturnType]
54
+ return item # type: ignore[return-value]
55
+
56
+
57
+ def encode_jsonl_line(item: model.ConversationItem) -> str:
58
+ return json.dumps(encode_conversation_item(item), ensure_ascii=False) + "\n"
59
+
60
+
61
+ def decode_jsonl_line(line: str) -> model.ConversationItem | None:
62
+ line = line.strip()
63
+ if not line:
64
+ return None
65
+ try:
66
+ obj = json.loads(line)
67
+ except json.JSONDecodeError:
68
+ return None
69
+ if not isinstance(obj, dict):
70
+ return None
71
+ return decode_conversation_item(cast(dict[str, Any], obj))