klaude-code 2.8.1__py3-none-any.whl → 2.9.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.
- klaude_code/app/runtime.py +2 -1
- klaude_code/auth/antigravity/oauth.py +0 -9
- klaude_code/auth/antigravity/token_manager.py +0 -18
- klaude_code/auth/base.py +53 -0
- klaude_code/auth/codex/exceptions.py +0 -4
- klaude_code/auth/codex/oauth.py +32 -28
- klaude_code/auth/codex/token_manager.py +0 -18
- klaude_code/cli/cost_cmd.py +128 -39
- klaude_code/cli/list_model.py +27 -10
- klaude_code/cli/main.py +14 -3
- klaude_code/config/assets/builtin_config.yaml +8 -24
- klaude_code/config/config.py +47 -25
- klaude_code/config/sub_agent_model_helper.py +18 -13
- klaude_code/config/thinking.py +0 -8
- klaude_code/const.py +1 -1
- klaude_code/core/agent_profile.py +10 -52
- klaude_code/core/compaction/overflow.py +0 -4
- klaude_code/core/executor.py +33 -5
- klaude_code/core/manager/llm_clients.py +9 -1
- klaude_code/core/prompts/prompt-claude-code.md +4 -4
- klaude_code/core/reminders.py +21 -23
- klaude_code/core/task.py +0 -4
- klaude_code/core/tool/__init__.py +3 -2
- klaude_code/core/tool/file/apply_patch.py +0 -27
- klaude_code/core/tool/file/read_tool.md +3 -2
- klaude_code/core/tool/file/read_tool.py +15 -2
- klaude_code/core/tool/offload.py +0 -35
- klaude_code/core/tool/sub_agent/__init__.py +6 -0
- klaude_code/core/tool/sub_agent/image_gen.md +16 -0
- klaude_code/core/tool/sub_agent/image_gen.py +146 -0
- klaude_code/core/tool/sub_agent/task.md +20 -0
- klaude_code/core/tool/sub_agent/task.py +205 -0
- klaude_code/core/tool/tool_registry.py +0 -16
- klaude_code/core/turn.py +1 -1
- klaude_code/llm/anthropic/input.py +6 -5
- klaude_code/llm/antigravity/input.py +14 -7
- klaude_code/llm/codex/client.py +22 -0
- klaude_code/llm/codex/prompt_sync.py +237 -0
- klaude_code/llm/google/client.py +8 -6
- klaude_code/llm/google/input.py +20 -12
- klaude_code/llm/image.py +18 -11
- klaude_code/llm/input_common.py +14 -6
- klaude_code/llm/json_stable.py +37 -0
- klaude_code/llm/openai_compatible/input.py +0 -10
- klaude_code/llm/openai_compatible/stream.py +16 -1
- klaude_code/llm/registry.py +0 -5
- klaude_code/llm/responses/input.py +15 -5
- klaude_code/llm/usage.py +0 -8
- klaude_code/protocol/events.py +2 -1
- klaude_code/protocol/message.py +2 -2
- klaude_code/protocol/model.py +20 -1
- klaude_code/protocol/op.py +13 -0
- klaude_code/protocol/op_handler.py +5 -0
- klaude_code/protocol/sub_agent/AGENTS.md +5 -5
- klaude_code/protocol/sub_agent/__init__.py +13 -34
- klaude_code/protocol/sub_agent/explore.py +7 -34
- klaude_code/protocol/sub_agent/image_gen.py +3 -74
- klaude_code/protocol/sub_agent/task.py +3 -47
- klaude_code/protocol/sub_agent/web.py +8 -52
- klaude_code/protocol/tools.py +2 -0
- klaude_code/session/session.py +58 -21
- klaude_code/session/store.py +0 -4
- klaude_code/skill/assets/deslop/SKILL.md +9 -0
- klaude_code/skill/system_skills.py +0 -20
- klaude_code/tui/command/fork_session_cmd.py +5 -2
- klaude_code/tui/command/resume_cmd.py +9 -2
- klaude_code/tui/command/sub_agent_model_cmd.py +85 -18
- klaude_code/tui/components/assistant.py +0 -26
- klaude_code/tui/components/command_output.py +3 -1
- klaude_code/tui/components/developer.py +3 -0
- klaude_code/tui/components/diffs.py +2 -208
- klaude_code/tui/components/errors.py +4 -0
- klaude_code/tui/components/mermaid_viewer.py +2 -2
- klaude_code/tui/components/rich/markdown.py +0 -54
- klaude_code/tui/components/rich/theme.py +2 -0
- klaude_code/tui/components/sub_agent.py +2 -46
- klaude_code/tui/components/thinking.py +0 -33
- klaude_code/tui/components/tools.py +43 -21
- klaude_code/tui/input/images.py +21 -18
- klaude_code/tui/input/key_bindings.py +2 -2
- klaude_code/tui/input/prompt_toolkit.py +49 -49
- klaude_code/tui/machine.py +15 -11
- klaude_code/tui/renderer.py +11 -20
- klaude_code/tui/runner.py +2 -1
- klaude_code/tui/terminal/image.py +6 -34
- klaude_code/ui/common.py +0 -70
- {klaude_code-2.8.1.dist-info → klaude_code-2.9.0.dist-info}/METADATA +3 -6
- {klaude_code-2.8.1.dist-info → klaude_code-2.9.0.dist-info}/RECORD +90 -86
- klaude_code/core/tool/sub_agent_tool.py +0 -126
- klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -108
- klaude_code/tui/components/rich/searchable_text.py +0 -68
- {klaude_code-2.8.1.dist-info → klaude_code-2.9.0.dist-info}/WHEEL +0 -0
- {klaude_code-2.8.1.dist-info → klaude_code-2.9.0.dist-info}/entry_points.txt +0 -0
klaude_code/llm/registry.py
CHANGED
|
@@ -38,11 +38,6 @@ def _load_protocol(protocol: llm_param.LLMClientProtocol) -> None:
|
|
|
38
38
|
_loaded_protocols.add(protocol)
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
def load_protocol(protocol: llm_param.LLMClientProtocol) -> None:
|
|
42
|
-
"""Load the module for a specific protocol on demand."""
|
|
43
|
-
_load_protocol(protocol)
|
|
44
|
-
|
|
45
|
-
|
|
46
41
|
def register(name: llm_param.LLMClientProtocol) -> Callable[[_T], _T]:
|
|
47
42
|
"""Decorator to register an LLM client class for a protocol."""
|
|
48
43
|
|
|
@@ -7,6 +7,7 @@ from typing import Any, cast
|
|
|
7
7
|
from openai.types import responses
|
|
8
8
|
|
|
9
9
|
from klaude_code.const import EMPTY_TOOL_OUTPUT_MESSAGE
|
|
10
|
+
from klaude_code.llm.image import image_file_to_data_url
|
|
10
11
|
from klaude_code.llm.input_common import (
|
|
11
12
|
DeveloperAttachment,
|
|
12
13
|
attach_developer_messages,
|
|
@@ -16,6 +17,12 @@ from klaude_code.llm.input_common import (
|
|
|
16
17
|
from klaude_code.protocol import llm_param, message
|
|
17
18
|
|
|
18
19
|
|
|
20
|
+
def _image_to_url(image: message.ImageURLPart | message.ImageFilePart) -> str:
|
|
21
|
+
if isinstance(image, message.ImageFilePart):
|
|
22
|
+
return image_file_to_data_url(image)
|
|
23
|
+
return image.url
|
|
24
|
+
|
|
25
|
+
|
|
19
26
|
def _build_user_content_parts(
|
|
20
27
|
user: message.UserMessage,
|
|
21
28
|
attachment: DeveloperAttachment,
|
|
@@ -24,11 +31,11 @@ def _build_user_content_parts(
|
|
|
24
31
|
for part in user.parts:
|
|
25
32
|
if isinstance(part, message.TextPart):
|
|
26
33
|
parts.append(cast(responses.ResponseInputContentParam, {"type": "input_text", "text": part.text}))
|
|
27
|
-
elif isinstance(part, message.ImageURLPart):
|
|
34
|
+
elif isinstance(part, (message.ImageURLPart, message.ImageFilePart)):
|
|
28
35
|
parts.append(
|
|
29
36
|
cast(
|
|
30
37
|
responses.ResponseInputContentParam,
|
|
31
|
-
{"type": "input_image", "detail": "auto", "image_url": part
|
|
38
|
+
{"type": "input_image", "detail": "auto", "image_url": _image_to_url(part)},
|
|
32
39
|
)
|
|
33
40
|
)
|
|
34
41
|
if attachment.text:
|
|
@@ -37,7 +44,7 @@ def _build_user_content_parts(
|
|
|
37
44
|
parts.append(
|
|
38
45
|
cast(
|
|
39
46
|
responses.ResponseInputContentParam,
|
|
40
|
-
{"type": "input_image", "detail": "auto", "image_url": image
|
|
47
|
+
{"type": "input_image", "detail": "auto", "image_url": _image_to_url(image)},
|
|
41
48
|
)
|
|
42
49
|
)
|
|
43
50
|
if not parts:
|
|
@@ -56,12 +63,15 @@ def _build_tool_result_item(
|
|
|
56
63
|
)
|
|
57
64
|
if text_output:
|
|
58
65
|
content_parts.append(cast(responses.ResponseInputContentParam, {"type": "input_text", "text": text_output}))
|
|
59
|
-
images
|
|
66
|
+
images: list[message.ImageURLPart | message.ImageFilePart] = [
|
|
67
|
+
part for part in tool.parts if isinstance(part, (message.ImageURLPart, message.ImageFilePart))
|
|
68
|
+
]
|
|
69
|
+
images.extend(attachment.images)
|
|
60
70
|
for image in images:
|
|
61
71
|
content_parts.append(
|
|
62
72
|
cast(
|
|
63
73
|
responses.ResponseInputContentParam,
|
|
64
|
-
{"type": "input_image", "detail": "auto", "image_url": image
|
|
74
|
+
{"type": "input_image", "detail": "auto", "image_url": _image_to_url(image)},
|
|
65
75
|
)
|
|
66
76
|
)
|
|
67
77
|
|
klaude_code/llm/usage.py
CHANGED
|
@@ -44,14 +44,6 @@ class MetadataTracker:
|
|
|
44
44
|
self._usage = model.Usage()
|
|
45
45
|
self._cost_config = cost_config
|
|
46
46
|
|
|
47
|
-
@property
|
|
48
|
-
def first_token_time(self) -> float | None:
|
|
49
|
-
return self._first_token_time
|
|
50
|
-
|
|
51
|
-
@property
|
|
52
|
-
def last_token_time(self) -> float | None:
|
|
53
|
-
return self._last_token_time
|
|
54
|
-
|
|
55
47
|
def record_token(self) -> None:
|
|
56
48
|
"""Record a token arrival, updating first/last token times."""
|
|
57
49
|
now = time.time()
|
klaude_code/protocol/events.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import time
|
|
4
|
+
from collections.abc import Sequence
|
|
4
5
|
from typing import Literal
|
|
5
6
|
|
|
6
7
|
from pydantic import BaseModel, Field
|
|
@@ -58,7 +59,7 @@ class ResponseEvent(Event):
|
|
|
58
59
|
|
|
59
60
|
class UserMessageEvent(Event):
|
|
60
61
|
content: str
|
|
61
|
-
images:
|
|
62
|
+
images: Sequence[message.ImageURLPart | message.ImageFilePart] | None = None
|
|
62
63
|
|
|
63
64
|
|
|
64
65
|
class DeveloperMessageEvent(Event):
|
klaude_code/protocol/message.py
CHANGED
|
@@ -213,7 +213,7 @@ class UserInputPayload(BaseModel):
|
|
|
213
213
|
"""
|
|
214
214
|
|
|
215
215
|
text: str
|
|
216
|
-
images:
|
|
216
|
+
images: Sequence[ImageURLPart | ImageFilePart] | None = None
|
|
217
217
|
|
|
218
218
|
|
|
219
219
|
# Helper functions
|
|
@@ -225,7 +225,7 @@ def text_parts_from_str(text: str | None) -> list[Part]:
|
|
|
225
225
|
return [TextPart(text=text)]
|
|
226
226
|
|
|
227
227
|
|
|
228
|
-
def parts_from_text_and_images(text: str | None, images:
|
|
228
|
+
def parts_from_text_and_images(text: str | None, images: Sequence[ImageURLPart | ImageFilePart] | None) -> list[Part]:
|
|
229
229
|
parts: list[Part] = []
|
|
230
230
|
if text:
|
|
231
231
|
parts.append(TextPart(text=text))
|
klaude_code/protocol/model.py
CHANGED
|
@@ -217,6 +217,11 @@ class MermaidLinkUIExtra(BaseModel):
|
|
|
217
217
|
line_count: int
|
|
218
218
|
|
|
219
219
|
|
|
220
|
+
class ImageUIExtra(BaseModel):
|
|
221
|
+
type: Literal["image"] = "image"
|
|
222
|
+
file_path: str
|
|
223
|
+
|
|
224
|
+
|
|
220
225
|
class MarkdownDocUIExtra(BaseModel):
|
|
221
226
|
type: Literal["markdown_doc"] = "markdown_doc"
|
|
222
227
|
file_path: str
|
|
@@ -231,7 +236,13 @@ class SessionStatusUIExtra(BaseModel):
|
|
|
231
236
|
|
|
232
237
|
|
|
233
238
|
MultiUIExtraItem = (
|
|
234
|
-
DiffUIExtra
|
|
239
|
+
DiffUIExtra
|
|
240
|
+
| TodoListUIExtra
|
|
241
|
+
| SessionIdUIExtra
|
|
242
|
+
| MermaidLinkUIExtra
|
|
243
|
+
| ImageUIExtra
|
|
244
|
+
| MarkdownDocUIExtra
|
|
245
|
+
| SessionStatusUIExtra
|
|
235
246
|
)
|
|
236
247
|
|
|
237
248
|
|
|
@@ -251,6 +262,7 @@ ToolResultUIExtra = Annotated[
|
|
|
251
262
|
| TodoListUIExtra
|
|
252
263
|
| SessionIdUIExtra
|
|
253
264
|
| MermaidLinkUIExtra
|
|
265
|
+
| ImageUIExtra
|
|
254
266
|
| MarkdownDocUIExtra
|
|
255
267
|
| SessionStatusUIExtra
|
|
256
268
|
| MultiUIExtra,
|
|
@@ -292,6 +304,7 @@ class AtFileOpsUIItem(BaseModel):
|
|
|
292
304
|
class UserImagesUIItem(BaseModel):
|
|
293
305
|
type: Literal["user_images"] = "user_images"
|
|
294
306
|
count: int
|
|
307
|
+
paths: list[str] = []
|
|
295
308
|
|
|
296
309
|
|
|
297
310
|
class SkillActivatedUIItem(BaseModel):
|
|
@@ -299,6 +312,11 @@ class SkillActivatedUIItem(BaseModel):
|
|
|
299
312
|
name: str
|
|
300
313
|
|
|
301
314
|
|
|
315
|
+
class AtFileImagesUIItem(BaseModel):
|
|
316
|
+
type: Literal["at_file_images"] = "at_file_images"
|
|
317
|
+
paths: list[str]
|
|
318
|
+
|
|
319
|
+
|
|
302
320
|
type DeveloperUIItem = (
|
|
303
321
|
MemoryLoadedUIItem
|
|
304
322
|
| ExternalFileChangesUIItem
|
|
@@ -306,6 +324,7 @@ type DeveloperUIItem = (
|
|
|
306
324
|
| AtFileOpsUIItem
|
|
307
325
|
| UserImagesUIItem
|
|
308
326
|
| SkillActivatedUIItem
|
|
327
|
+
| AtFileImagesUIItem
|
|
309
328
|
)
|
|
310
329
|
|
|
311
330
|
|
klaude_code/protocol/op.py
CHANGED
|
@@ -27,6 +27,7 @@ class OperationType(Enum):
|
|
|
27
27
|
CONTINUE_AGENT = "continue_agent"
|
|
28
28
|
COMPACT_SESSION = "compact_session"
|
|
29
29
|
CHANGE_MODEL = "change_model"
|
|
30
|
+
CHANGE_COMPACT_MODEL = "change_compact_model"
|
|
30
31
|
CHANGE_SUB_AGENT_MODEL = "change_sub_agent_model"
|
|
31
32
|
CHANGE_THINKING = "change_thinking"
|
|
32
33
|
CLEAR_SESSION = "clear_session"
|
|
@@ -108,6 +109,18 @@ class ChangeModelOperation(Operation):
|
|
|
108
109
|
await handler.handle_change_model(self)
|
|
109
110
|
|
|
110
111
|
|
|
112
|
+
class ChangeCompactModelOperation(Operation):
|
|
113
|
+
"""Operation for changing the compact model (used for session compaction)."""
|
|
114
|
+
|
|
115
|
+
type: OperationType = OperationType.CHANGE_COMPACT_MODEL
|
|
116
|
+
session_id: str
|
|
117
|
+
model_name: str | None
|
|
118
|
+
save_as_default: bool = False
|
|
119
|
+
|
|
120
|
+
async def execute(self, handler: OperationHandler) -> None:
|
|
121
|
+
await handler.handle_change_compact_model(self)
|
|
122
|
+
|
|
123
|
+
|
|
111
124
|
class ChangeThinkingOperation(Operation):
|
|
112
125
|
"""Operation for changing the thinking/reasoning configuration."""
|
|
113
126
|
|
|
@@ -10,6 +10,7 @@ from typing import TYPE_CHECKING, Protocol
|
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
12
|
from klaude_code.protocol.op import (
|
|
13
|
+
ChangeCompactModelOperation,
|
|
13
14
|
ChangeModelOperation,
|
|
14
15
|
ChangeSubAgentModelOperation,
|
|
15
16
|
ChangeThinkingOperation,
|
|
@@ -43,6 +44,10 @@ class OperationHandler(Protocol):
|
|
|
43
44
|
"""Handle a change model operation."""
|
|
44
45
|
...
|
|
45
46
|
|
|
47
|
+
async def handle_change_compact_model(self, operation: ChangeCompactModelOperation) -> None:
|
|
48
|
+
"""Handle a change compact model operation."""
|
|
49
|
+
...
|
|
50
|
+
|
|
46
51
|
async def handle_change_thinking(self, operation: ChangeThinkingOperation) -> None:
|
|
47
52
|
"""Handle a change thinking operation."""
|
|
48
53
|
...
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Sub-Agent Protocol
|
|
2
2
|
|
|
3
|
-
Sub-agents are specialized
|
|
3
|
+
Sub-agents are specialized agent types invoked by tools like Task and ImageGen. This module defines profiles and registration.
|
|
4
4
|
|
|
5
5
|
## Key Constraint
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ The `protocol` layer cannot import from `config` or `core` (enforced by import-l
|
|
|
9
9
|
## Core Files
|
|
10
10
|
|
|
11
11
|
- `__init__.py` - `SubAgentProfile` dataclass and registration. Defines `AVAILABILITY_*` constants.
|
|
12
|
-
- `image_gen.py`, `task.py`, `explore.py`, `web.py` - Individual sub-agent definitions.
|
|
12
|
+
- `image_gen.py`, `task.py`, `explore.py`, `web.py` - Individual sub-agent type definitions.
|
|
13
13
|
|
|
14
14
|
## Availability Requirement Flow
|
|
15
15
|
|
|
@@ -23,6 +23,6 @@ Some sub-agents require specific model capabilities (e.g., ImageGen needs an ima
|
|
|
23
23
|
## Model Selection
|
|
24
24
|
|
|
25
25
|
For sub-agents with `availability_requirement`, priority is:
|
|
26
|
-
1. Explicit config in `sub_agent_models`
|
|
27
|
-
2.
|
|
28
|
-
3.
|
|
26
|
+
1. Explicit config in `sub_agent_models` for the specific type
|
|
27
|
+
2. Fallback to the Task model config (if present)
|
|
28
|
+
3. Otherwise inherit the main agent model
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable
|
|
4
|
-
from dataclasses import dataclass
|
|
4
|
+
from dataclasses import dataclass
|
|
5
5
|
from typing import TYPE_CHECKING, Any
|
|
6
6
|
|
|
7
7
|
from klaude_code.protocol import tools
|
|
@@ -38,32 +38,22 @@ class SubAgentProfile:
|
|
|
38
38
|
3. Build the prompt for the sub agent
|
|
39
39
|
"""
|
|
40
40
|
|
|
41
|
-
# Identity - single name used for type,
|
|
42
|
-
name: str # e.g., "Task", "Explore", "
|
|
41
|
+
# Identity - single name used for type, config_key, and prompt_key
|
|
42
|
+
name: str # e.g., "Task", "Explore", "Web", "ImageGen"
|
|
43
43
|
|
|
44
|
-
#
|
|
45
|
-
description: str # Tool description shown to the main agent
|
|
46
|
-
parameters: dict[str, Any] = field(
|
|
47
|
-
default_factory=lambda: dict[str, Any](), hash=False
|
|
48
|
-
) # JSON Schema for tool parameters
|
|
49
|
-
|
|
50
|
-
# System prompt
|
|
44
|
+
# Sub-agent run configuration
|
|
51
45
|
prompt_file: str = "" # Resource file path relative to core package (e.g., "prompts/prompt-sub-agent.md")
|
|
52
|
-
|
|
53
|
-
# Sub agent configuration
|
|
54
46
|
tool_set: tuple[str, ...] = () # Tools available to this sub agent
|
|
55
47
|
prompt_builder: PromptBuilder = _default_prompt_builder # Builds the sub agent prompt from tool arguments
|
|
56
48
|
|
|
49
|
+
# Entry-point metadata for Task tool (RunSubAgent)
|
|
50
|
+
invoker_type: str | None = None # Tool-level type mapping (e.g., "general-purpose", "explore", "web")
|
|
51
|
+
invoker_summary: str = "" # Short description shown under Task tool supported types
|
|
52
|
+
standalone_tool: bool = False # True for sub-agents invoked by dedicated tools (e.g., ImageGen)
|
|
53
|
+
|
|
57
54
|
# UI display
|
|
58
55
|
active_form: str = "" # Active form for spinner status (e.g., "Tasking", "Exploring")
|
|
59
56
|
|
|
60
|
-
# Availability
|
|
61
|
-
enabled_by_default: bool = True
|
|
62
|
-
show_in_main_agent: bool = True
|
|
63
|
-
|
|
64
|
-
# Structured output support: specifies which parameter in the tool schema contains the output schema
|
|
65
|
-
output_schema_arg: str | None = None
|
|
66
|
-
|
|
67
57
|
# Config-based availability requirement (e.g., "image_model" means requires an image model)
|
|
68
58
|
# The actual check is performed in the core layer to avoid circular imports.
|
|
69
59
|
availability_requirement: str | None = None
|
|
@@ -85,25 +75,14 @@ def get_sub_agent_profile(sub_agent_type: tools.SubAgentType) -> SubAgentProfile
|
|
|
85
75
|
raise KeyError(f"Unknown sub agent type: {sub_agent_type}") from exc
|
|
86
76
|
|
|
87
77
|
|
|
88
|
-
def iter_sub_agent_profiles(
|
|
89
|
-
|
|
90
|
-
if not enabled_only:
|
|
91
|
-
return profiles
|
|
92
|
-
return [p for p in profiles if p.enabled_by_default]
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def get_sub_agent_profile_by_tool(tool_name: str) -> SubAgentProfile | None:
|
|
96
|
-
return _PROFILES.get(tool_name)
|
|
78
|
+
def iter_sub_agent_profiles() -> list[SubAgentProfile]:
|
|
79
|
+
return list(_PROFILES.values())
|
|
97
80
|
|
|
98
81
|
|
|
99
82
|
def is_sub_agent_tool(tool_name: str) -> bool:
|
|
100
|
-
|
|
101
|
-
|
|
83
|
+
from klaude_code.protocol import tools
|
|
102
84
|
|
|
103
|
-
|
|
104
|
-
return [
|
|
105
|
-
profile.name for profile in iter_sub_agent_profiles(enabled_only=enabled_only) if profile.show_in_main_agent
|
|
106
|
-
]
|
|
85
|
+
return tool_name in {tools.TASK, tools.IMAGE_GEN}
|
|
107
86
|
|
|
108
87
|
|
|
109
88
|
# Import sub-agent modules to trigger registration
|
|
@@ -3,46 +3,19 @@ from __future__ import annotations
|
|
|
3
3
|
from klaude_code.protocol import tools
|
|
4
4
|
from klaude_code.protocol.sub_agent import SubAgentProfile, register_sub_agent
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
EXPLORE_PARAMETERS = {
|
|
14
|
-
"type": "object",
|
|
15
|
-
"properties": {
|
|
16
|
-
"resume": {
|
|
17
|
-
"type": "string",
|
|
18
|
-
"description": "Optional agent ID to resume from. If provided, the agent will continue from the previous execution transcript.",
|
|
19
|
-
},
|
|
20
|
-
"description": {
|
|
21
|
-
"type": "string",
|
|
22
|
-
"description": "Short (3-5 words) label for the exploration goal",
|
|
23
|
-
},
|
|
24
|
-
"prompt": {
|
|
25
|
-
"type": "string",
|
|
26
|
-
"description": "The task for the agent to perform",
|
|
27
|
-
},
|
|
28
|
-
"output_format": {
|
|
29
|
-
"type": "object",
|
|
30
|
-
"description": "Optional JSON Schema for sub-agent structured output",
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
"required": ["description", "prompt"],
|
|
34
|
-
"additionalProperties": False,
|
|
35
|
-
}
|
|
36
|
-
|
|
6
|
+
EXPLORE_SUMMARY = (
|
|
7
|
+
"Fast codebase exploration: find files by patterns, search for keywords, and summarize how things work.\n"
|
|
8
|
+
"Always spawn multiple search agents in parallel to maximise speed. "
|
|
9
|
+
"(Tools: Bash, Read)"
|
|
10
|
+
)
|
|
37
11
|
|
|
38
12
|
register_sub_agent(
|
|
39
13
|
SubAgentProfile(
|
|
40
14
|
name="Explore",
|
|
41
|
-
description=EXPLORE_DESCRIPTION,
|
|
42
|
-
parameters=EXPLORE_PARAMETERS,
|
|
43
15
|
prompt_file="prompts/prompt-sub-agent-explore.md",
|
|
44
16
|
tool_set=(tools.BASH, tools.READ),
|
|
17
|
+
invoker_type="explore",
|
|
18
|
+
invoker_summary=EXPLORE_SUMMARY,
|
|
45
19
|
active_form="Exploring",
|
|
46
|
-
output_schema_arg="output_format",
|
|
47
20
|
)
|
|
48
21
|
)
|
|
@@ -4,76 +4,6 @@ from typing import Any, cast
|
|
|
4
4
|
|
|
5
5
|
from klaude_code.protocol.sub_agent import AVAILABILITY_IMAGE_MODEL, SubAgentProfile, register_sub_agent
|
|
6
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
|
-
|
|
35
|
-
|
|
36
|
-
IMAGE_GEN_PARAMETERS: dict[str, Any] = {
|
|
37
|
-
"type": "object",
|
|
38
|
-
"properties": {
|
|
39
|
-
"resume": {
|
|
40
|
-
"type": "string",
|
|
41
|
-
"description": "Optional agent ID to resume from. If provided, the agent will continue from the previous execution transcript.",
|
|
42
|
-
},
|
|
43
|
-
"description": {
|
|
44
|
-
"type": "string",
|
|
45
|
-
"description": "A short (3-5 word) description of the request.",
|
|
46
|
-
},
|
|
47
|
-
"prompt": {
|
|
48
|
-
"type": "string",
|
|
49
|
-
"description": "Text prompt for image generation.",
|
|
50
|
-
},
|
|
51
|
-
"image_paths": {
|
|
52
|
-
"type": "array",
|
|
53
|
-
"items": {"type": "string"},
|
|
54
|
-
"description": "Optional local image file paths used as references.",
|
|
55
|
-
},
|
|
56
|
-
"generation": {
|
|
57
|
-
"type": "object",
|
|
58
|
-
"description": "Optional per-call image generation settings.",
|
|
59
|
-
"properties": {
|
|
60
|
-
"aspect_ratio": {
|
|
61
|
-
"type": "string",
|
|
62
|
-
"description": "Aspect ratio, e.g. '16:9', '1:1', '9:16'.",
|
|
63
|
-
},
|
|
64
|
-
"image_size": {
|
|
65
|
-
"type": "string",
|
|
66
|
-
"enum": ["1K", "2K", "4K"],
|
|
67
|
-
"description": "Output size for Nano Banana Pro (must use uppercase K).",
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
"additionalProperties": False,
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
"required": ["prompt"],
|
|
74
|
-
"additionalProperties": False,
|
|
75
|
-
}
|
|
76
|
-
|
|
77
7
|
|
|
78
8
|
def _quote_at_pattern_path(path: str) -> str:
|
|
79
9
|
if any(ch.isspace() for ch in path) or '"' in path:
|
|
@@ -82,7 +12,7 @@ def _quote_at_pattern_path(path: str) -> str:
|
|
|
82
12
|
return f"@{path}"
|
|
83
13
|
|
|
84
14
|
|
|
85
|
-
def
|
|
15
|
+
def build_image_gen_prompt(args: dict[str, Any]) -> str:
|
|
86
16
|
prompt = str(args.get("prompt") or "").strip()
|
|
87
17
|
image_paths = args.get("image_paths")
|
|
88
18
|
|
|
@@ -98,12 +28,11 @@ def _build_image_gen_prompt(args: dict[str, Any]) -> str:
|
|
|
98
28
|
register_sub_agent(
|
|
99
29
|
SubAgentProfile(
|
|
100
30
|
name="ImageGen",
|
|
101
|
-
description=IMAGE_GEN_DESCRIPTION,
|
|
102
|
-
parameters=IMAGE_GEN_PARAMETERS,
|
|
103
31
|
prompt_file="prompts/prompt-sub-agent-image-gen.md",
|
|
104
32
|
tool_set=(),
|
|
105
|
-
prompt_builder=
|
|
33
|
+
prompt_builder=build_image_gen_prompt,
|
|
106
34
|
active_form="Generating Image",
|
|
107
35
|
availability_requirement=AVAILABILITY_IMAGE_MODEL,
|
|
36
|
+
standalone_tool=True,
|
|
108
37
|
)
|
|
109
38
|
)
|
|
@@ -3,59 +3,15 @@ from __future__ import annotations
|
|
|
3
3
|
from klaude_code.protocol import tools
|
|
4
4
|
from klaude_code.protocol.sub_agent import SubAgentProfile, register_sub_agent
|
|
5
5
|
|
|
6
|
-
|
|
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
|
-
|
|
25
|
-
TASK_PARAMETERS = {
|
|
26
|
-
"type": "object",
|
|
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
|
-
},
|
|
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
|
-
}
|
|
6
|
+
TASK_SUMMARY = "General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. (Tools: All Tools)"
|
|
50
7
|
|
|
51
8
|
register_sub_agent(
|
|
52
9
|
SubAgentProfile(
|
|
53
10
|
name="Task",
|
|
54
|
-
description=TASK_DESCRIPTION,
|
|
55
|
-
parameters=TASK_PARAMETERS,
|
|
56
11
|
prompt_file="prompts/prompt-sub-agent.md",
|
|
57
12
|
tool_set=(tools.BASH, tools.READ, tools.EDIT, tools.WRITE),
|
|
13
|
+
invoker_type="general-purpose",
|
|
14
|
+
invoker_summary=TASK_SUMMARY,
|
|
58
15
|
active_form="Tasking",
|
|
59
|
-
output_schema_arg="output_format",
|
|
60
16
|
)
|
|
61
17
|
)
|
|
@@ -3,63 +3,19 @@ from __future__ import annotations
|
|
|
3
3
|
from klaude_code.protocol import tools
|
|
4
4
|
from klaude_code.protocol.sub_agent import SubAgentProfile, register_sub_agent
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- Gathering comprehensive information from multiple web sources
|
|
12
|
-
|
|
13
|
-
Capabilities:
|
|
14
|
-
- Search the web to find relevant pages
|
|
15
|
-
- Fetch and parse web pages
|
|
16
|
-
- Follow links across multiple pages
|
|
17
|
-
- Aggregate findings from multiple sources
|
|
18
|
-
|
|
19
|
-
How to use:
|
|
20
|
-
- Write a clear prompt describing what information you need - the agent will search and fetch as needed
|
|
21
|
-
- 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.
|
|
22
|
-
- Provide the url if you already know the target page
|
|
23
|
-
|
|
24
|
-
What you receive:
|
|
25
|
-
- The agent returns a text response summarizing its findings
|
|
26
|
-
- The response is the agent's analysis, not raw web content
|
|
27
|
-
- Web content is saved to local files (paths included in Sources) - read them directly if you need full content
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
WEB_AGENT_PARAMETERS = {
|
|
31
|
-
"type": "object",
|
|
32
|
-
"properties": {
|
|
33
|
-
"resume": {
|
|
34
|
-
"type": "string",
|
|
35
|
-
"description": "Optional agent ID to resume from. If provided, the agent will continue from the previous execution transcript.",
|
|
36
|
-
},
|
|
37
|
-
"description": {
|
|
38
|
-
"type": "string",
|
|
39
|
-
"description": "A short (3-5 word) description of the task",
|
|
40
|
-
},
|
|
41
|
-
"prompt": {
|
|
42
|
-
"type": "string",
|
|
43
|
-
"description": "Instructions for searching, analyzing, or extracting content from the web page",
|
|
44
|
-
},
|
|
45
|
-
"output_format": {
|
|
46
|
-
"type": "object",
|
|
47
|
-
"description": "Optional JSON Schema for sub-agent structured output",
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
"required": ["description", "prompt"],
|
|
51
|
-
"additionalProperties": False,
|
|
52
|
-
}
|
|
53
|
-
|
|
6
|
+
WEB_SUMMARY = (
|
|
7
|
+
"Web research: search, fetch, and analyze pages for up-to-date info; summarize findings with sources. "
|
|
8
|
+
"Include dates in queries when recency matters. "
|
|
9
|
+
"(Tools: WebSearch, WebFetch, Bash, Read, Write)"
|
|
10
|
+
)
|
|
54
11
|
|
|
55
12
|
register_sub_agent(
|
|
56
13
|
SubAgentProfile(
|
|
57
|
-
name="
|
|
58
|
-
description=WEB_AGENT_DESCRIPTION,
|
|
59
|
-
parameters=WEB_AGENT_PARAMETERS,
|
|
14
|
+
name="Web",
|
|
60
15
|
prompt_file="prompts/prompt-sub-agent-web.md",
|
|
61
16
|
tool_set=(tools.BASH, tools.READ, tools.WEB_FETCH, tools.WEB_SEARCH, tools.WRITE),
|
|
17
|
+
invoker_type="web",
|
|
18
|
+
invoker_summary=WEB_SUMMARY,
|
|
62
19
|
active_form="Surfing",
|
|
63
|
-
output_schema_arg="output_format",
|
|
64
20
|
)
|
|
65
21
|
)
|
klaude_code/protocol/tools.py
CHANGED
|
@@ -10,6 +10,8 @@ MERMAID = "Mermaid"
|
|
|
10
10
|
WEB_FETCH = "WebFetch"
|
|
11
11
|
WEB_SEARCH = "WebSearch"
|
|
12
12
|
REPORT_BACK = "report_back"
|
|
13
|
+
TASK = "Task"
|
|
14
|
+
IMAGE_GEN = "ImageGen"
|
|
13
15
|
|
|
14
16
|
# SubAgentType is just a string alias now; agent types are defined via SubAgentProfile
|
|
15
17
|
SubAgentType = str
|