klaude-code 1.2.15__py3-none-any.whl → 1.2.17__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 (59) hide show
  1. klaude_code/cli/main.py +66 -42
  2. klaude_code/cli/runtime.py +34 -13
  3. klaude_code/command/__init__.py +3 -0
  4. klaude_code/command/export_cmd.py +2 -2
  5. klaude_code/command/export_online_cmd.py +149 -0
  6. klaude_code/command/prompt-handoff.md +33 -0
  7. klaude_code/command/thinking_cmd.py +5 -1
  8. klaude_code/config/config.py +20 -21
  9. klaude_code/config/list_model.py +1 -1
  10. klaude_code/const/__init__.py +3 -0
  11. klaude_code/core/executor.py +2 -2
  12. klaude_code/core/manager/llm_clients_builder.py +1 -1
  13. klaude_code/core/manager/sub_agent_manager.py +30 -6
  14. klaude_code/core/prompt.py +15 -13
  15. klaude_code/core/prompts/{prompt-subagent-explore.md → prompt-sub-agent-explore.md} +0 -1
  16. klaude_code/core/prompts/{prompt-subagent-oracle.md → prompt-sub-agent-oracle.md} +1 -2
  17. klaude_code/core/prompts/prompt-sub-agent-web.md +48 -0
  18. klaude_code/core/reminders.py +75 -32
  19. klaude_code/core/task.py +18 -22
  20. klaude_code/core/tool/__init__.py +4 -0
  21. klaude_code/core/tool/report_back_tool.py +84 -0
  22. klaude_code/core/tool/sub_agent_tool.py +6 -0
  23. klaude_code/core/tool/tool_runner.py +9 -1
  24. klaude_code/core/tool/web/web_search_tool.md +23 -0
  25. klaude_code/core/tool/web/web_search_tool.py +126 -0
  26. klaude_code/core/turn.py +45 -4
  27. klaude_code/llm/anthropic/input.py +14 -5
  28. klaude_code/llm/openrouter/input.py +14 -3
  29. klaude_code/llm/responses/input.py +19 -0
  30. klaude_code/protocol/commands.py +1 -0
  31. klaude_code/protocol/events.py +9 -0
  32. klaude_code/protocol/model.py +24 -14
  33. klaude_code/protocol/sub_agent/__init__.py +117 -0
  34. klaude_code/protocol/sub_agent/explore.py +63 -0
  35. klaude_code/protocol/sub_agent/oracle.py +91 -0
  36. klaude_code/protocol/sub_agent/task.py +61 -0
  37. klaude_code/protocol/sub_agent/web.py +78 -0
  38. klaude_code/protocol/tools.py +2 -0
  39. klaude_code/session/export.py +12 -6
  40. klaude_code/session/session.py +12 -2
  41. klaude_code/session/templates/export_session.html +111 -36
  42. klaude_code/ui/modes/repl/completers.py +1 -1
  43. klaude_code/ui/modes/repl/event_handler.py +65 -8
  44. klaude_code/ui/modes/repl/renderer.py +11 -9
  45. klaude_code/ui/renderers/developer.py +18 -7
  46. klaude_code/ui/renderers/metadata.py +24 -12
  47. klaude_code/ui/renderers/sub_agent.py +63 -3
  48. klaude_code/ui/renderers/thinking.py +1 -1
  49. klaude_code/ui/renderers/tools.py +24 -37
  50. klaude_code/ui/rich/markdown.py +20 -48
  51. klaude_code/ui/rich/status.py +61 -17
  52. klaude_code/ui/rich/theme.py +8 -7
  53. {klaude_code-1.2.15.dist-info → klaude_code-1.2.17.dist-info}/METADATA +114 -22
  54. {klaude_code-1.2.15.dist-info → klaude_code-1.2.17.dist-info}/RECORD +57 -48
  55. klaude_code/core/prompts/prompt-subagent-webfetch.md +0 -46
  56. klaude_code/protocol/sub_agent.py +0 -354
  57. /klaude_code/core/prompts/{prompt-subagent.md → prompt-sub-agent.md} +0 -0
  58. {klaude_code-1.2.15.dist-info → klaude_code-1.2.17.dist-info}/WHEEL +0 -0
  59. {klaude_code-1.2.15.dist-info → klaude_code-1.2.17.dist-info}/entry_points.txt +0 -0
@@ -1,354 +0,0 @@
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
- # Sub agent configuration
49
- tool_set: tuple[str, ...] = () # Tools available to this sub agent
50
- prompt_builder: PromptBuilder = _default_prompt_builder # Builds the sub agent prompt from tool arguments
51
-
52
- # UI display
53
- active_form: str = "" # Active form for spinner status (e.g., "Tasking", "Exploring")
54
-
55
- # Availability
56
- enabled_by_default: bool = True
57
- show_in_main_agent: bool = True
58
- target_model_filter: AvailabilityPredicate | None = None
59
-
60
- def enabled_for_model(self, model_name: str | None) -> bool:
61
- if not self.enabled_by_default:
62
- return False
63
- if model_name is None or self.target_model_filter is None:
64
- return True
65
- return self.target_model_filter(model_name)
66
-
67
-
68
- _PROFILES: dict[str, SubAgentProfile] = {}
69
-
70
-
71
- def register_sub_agent(profile: SubAgentProfile) -> None:
72
- if profile.name in _PROFILES:
73
- raise ValueError(f"Duplicate sub agent profile: {profile.name}")
74
- _PROFILES[profile.name] = profile
75
-
76
-
77
- def get_sub_agent_profile(sub_agent_type: tools.SubAgentType) -> SubAgentProfile:
78
- try:
79
- return _PROFILES[sub_agent_type]
80
- except KeyError as exc:
81
- raise KeyError(f"Unknown sub agent type: {sub_agent_type}") from exc
82
-
83
-
84
- def iter_sub_agent_profiles(enabled_only: bool = False, model_name: str | None = None) -> list[SubAgentProfile]:
85
- profiles = list(_PROFILES.values())
86
- if not enabled_only:
87
- return profiles
88
- return [p for p in profiles if p.enabled_for_model(model_name)]
89
-
90
-
91
- def get_sub_agent_profile_by_tool(tool_name: str) -> SubAgentProfile | None:
92
- return _PROFILES.get(tool_name)
93
-
94
-
95
- def is_sub_agent_tool(tool_name: str) -> bool:
96
- return tool_name in _PROFILES
97
-
98
-
99
- def sub_agent_tool_names(enabled_only: bool = False, model_name: str | None = None) -> list[str]:
100
- return [
101
- profile.name
102
- for profile in iter_sub_agent_profiles(enabled_only=enabled_only, model_name=model_name)
103
- if profile.show_in_main_agent
104
- ]
105
-
106
-
107
- # -----------------------------------------------------------------------------
108
- # Sub Agent Definitions
109
- # -----------------------------------------------------------------------------
110
-
111
- TASK_DESCRIPTION = """\
112
- Launch a new agent to handle complex, multi-step tasks autonomously. \
113
-
114
- When NOT to use the Task tool:
115
- - 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
116
- - 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
117
- - 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
118
- - Other tasks that are not related to the agent descriptions above
119
-
120
- Usage notes:
121
- - Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
122
- - 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.
123
- - 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.
124
- - The agent's outputs should generally be trusted
125
- - 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
126
- - 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.
127
- - 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.\
128
- """
129
-
130
- TASK_PARAMETERS = {
131
- "type": "object",
132
- "properties": {
133
- "description": {
134
- "type": "string",
135
- "description": "A short (3-5 word) description of the task",
136
- },
137
- "prompt": {
138
- "type": "string",
139
- "description": "The task for the agent to perform",
140
- },
141
- },
142
- "required": ["description", "prompt"],
143
- "additionalProperties": False,
144
- }
145
-
146
- register_sub_agent(
147
- SubAgentProfile(
148
- name="Task",
149
- description=TASK_DESCRIPTION,
150
- parameters=TASK_PARAMETERS,
151
- tool_set=(tools.BASH, tools.READ, tools.EDIT, tools.WRITE),
152
- active_form="Tasking",
153
- )
154
- )
155
-
156
-
157
- # -----------------------------------------------------------------------------
158
- # Oracle Sub Agent
159
- # -----------------------------------------------------------------------------
160
-
161
- ORACLE_DESCRIPTION = """\
162
- Consult the Oracle - an AI advisor powered by OpenAI's premium reasoning model that can plan, review, and provide expert guidance.
163
-
164
- The Oracle has access to the following tools: Read, Bash.
165
-
166
- The Oracle acts as your senior engineering advisor and can help with:
167
-
168
- WHEN TO USE THE ORACLE:
169
- - Code reviews and architecture feedback
170
- - Finding a bug in multiple files
171
- - Planning complex implementations or refactoring
172
- - Analyzing code quality and suggesting improvements
173
- - Answering complex technical questions that require deep reasoning
174
-
175
- WHEN NOT TO USE THE ORACLE:
176
- - Simple file reading or searching tasks (use Read or Grep directly)
177
- - Codebase searches (use Task)
178
- - Basic code modifications and when you need to execute code changes (do it yourself or use Task)
179
-
180
- USAGE GUIDELINES:
181
- 1. Be specific about what you want the Oracle to review, plan, or debug
182
- 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.
183
-
184
-
185
- EXAMPLES:
186
- - "Review the authentication system architecture and suggest improvements"
187
- - "Plan the implementation of real-time collaboration features"
188
- - "Analyze the performance bottlenecks in the data processing pipeline"
189
- - "Review this API design and suggest better patterns"\
190
- """
191
-
192
- ORACLE_PARAMETERS = {
193
- "properties": {
194
- "context": {
195
- "description": "Optional context about the current situation, what you've tried, or background information that would help the Oracle provide better guidance.",
196
- "type": "string",
197
- },
198
- "files": {
199
- "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.",
200
- "items": {"type": "string"},
201
- "type": "array",
202
- },
203
- "task": {
204
- "description": "The task or question you want the Oracle to help with. Be specific about what kind of guidance, review, or planning you need.",
205
- "type": "string",
206
- },
207
- "description": {
208
- "description": "A short (3-5 word) description of the task",
209
- "type": "string",
210
- },
211
- },
212
- "required": ["task", "description"],
213
- "type": "object",
214
- }
215
-
216
-
217
- def _oracle_prompt_builder(args: dict[str, Any]) -> str:
218
- """Build the Oracle prompt from tool arguments."""
219
- context = args.get("context", "")
220
- task = args.get("task", "")
221
- files = args.get("files", [])
222
-
223
- prompt = f"""Context: {context}
224
-
225
- Task: {task}
226
- """
227
- if files:
228
- files_str = "\n".join(f"@{file}" for file in files)
229
- prompt += f"\nRelated files to review:\n{files_str}"
230
- return prompt
231
-
232
-
233
- register_sub_agent(
234
- SubAgentProfile(
235
- name="Oracle",
236
- description=ORACLE_DESCRIPTION,
237
- parameters=ORACLE_PARAMETERS,
238
- tool_set=(tools.READ, tools.BASH),
239
- prompt_builder=_oracle_prompt_builder,
240
- active_form="Consulting Oracle",
241
- target_model_filter=lambda model: ("gpt-5" not in model) and ("gemini-3" not in model),
242
- )
243
- )
244
-
245
-
246
- # -----------------------------------------------------------------------------
247
- # Explore Sub Agent
248
- # -----------------------------------------------------------------------------
249
-
250
- EXPLORE_DESCRIPTION = """\
251
- Spin up a fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), \
252
- search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?")\
253
- 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.
254
- Always spawn multiple search agents in parallel to maximise speed.\
255
- """
256
-
257
- EXPLORE_PARAMETERS = {
258
- "type": "object",
259
- "properties": {
260
- "description": {
261
- "type": "string",
262
- "description": "Short (3-5 words) label for the exploration goal",
263
- },
264
- "prompt": {
265
- "type": "string",
266
- "description": "The task for the agent to perform",
267
- },
268
- "thoroughness": {
269
- "type": "string",
270
- "enum": ["quick", "medium", "very thorough"],
271
- "description": "Controls how deep the sub-agent should search the repo",
272
- },
273
- },
274
- "required": ["description", "prompt"],
275
- "additionalProperties": False,
276
- }
277
-
278
-
279
- def _explore_prompt_builder(args: dict[str, Any]) -> str:
280
- """Build the Explore prompt from tool arguments."""
281
- prompt = args.get("prompt", "").strip()
282
- thoroughness = args.get("thoroughness", "medium")
283
- return f"{prompt}\nthoroughness: {thoroughness}"
284
-
285
-
286
- register_sub_agent(
287
- SubAgentProfile(
288
- name="Explore",
289
- description=EXPLORE_DESCRIPTION,
290
- parameters=EXPLORE_PARAMETERS,
291
- tool_set=(tools.BASH, tools.READ),
292
- prompt_builder=_explore_prompt_builder,
293
- active_form="Exploring",
294
- )
295
- )
296
-
297
-
298
- # -----------------------------------------------------------------------------
299
- # WebFetchAgent Sub Agent
300
- # -----------------------------------------------------------------------------
301
-
302
- WEB_FETCH_AGENT_DESCRIPTION = """\
303
- Launch a sub-agent to fetch and analyze web content. Use this when you need to:
304
- - Retrieve and extract information from a webpage
305
- - Analyze web page content based on specific instructions
306
- - Get structured data from URLs
307
-
308
- The agent will fetch the URL content, handle HTML-to-Markdown conversion automatically, \
309
- and can use tools like rg to search through large responses that were truncated and saved to files.
310
-
311
- Usage notes:
312
- - Provide a clear prompt describing what information to extract or analyze
313
- - The agent will return a summary of the findings
314
- - For large web pages, the content may be truncated and saved to a file; the agent can search through it\
315
- """
316
-
317
- WEB_FETCH_AGENT_PARAMETERS = {
318
- "type": "object",
319
- "properties": {
320
- "description": {
321
- "type": "string",
322
- "description": "A short (3-5 word) description of the task",
323
- },
324
- "url": {
325
- "type": "string",
326
- "description": "The URL to fetch and analyze",
327
- },
328
- "prompt": {
329
- "type": "string",
330
- "description": "Instructions for analyzing or extracting content from the web page",
331
- },
332
- },
333
- "required": ["description", "url", "prompt"],
334
- "additionalProperties": False,
335
- }
336
-
337
-
338
- def _web_fetch_prompt_builder(args: dict[str, Any]) -> str:
339
- """Build the WebFetchAgent prompt from tool arguments."""
340
- url = args.get("url", "")
341
- prompt = args.get("prompt", "")
342
- return f"URL to fetch: {url}\nTask: {prompt}"
343
-
344
-
345
- register_sub_agent(
346
- SubAgentProfile(
347
- name="WebFetchAgent",
348
- description=WEB_FETCH_AGENT_DESCRIPTION,
349
- parameters=WEB_FETCH_AGENT_PARAMETERS,
350
- tool_set=(tools.BASH, tools.READ, tools.WEB_FETCH),
351
- prompt_builder=_web_fetch_prompt_builder,
352
- active_form="Fetching Web",
353
- )
354
- )