clawd-code-sdk 0.3.6__tar.gz → 0.3.7__tar.gz
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.
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/PKG-INFO +1 -1
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/pyproject.toml +1 -1
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/__init__.py +12 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/agents.py +1 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/base.py +2 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/hooks.py +3 -1
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/input_types.py +27 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/messages.py +15 -24
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/output_types.py +100 -4
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/e2e/test_agents_and_settings.py +2 -2
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/e2e/test_dynamic_control.py +6 -27
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/e2e/test_hook_events.py +1 -1
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/e2e/test_hooks.py +1 -1
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/e2e/test_include_partial_messages.py +15 -12
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/e2e/test_mcp_tools.py +3 -3
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/e2e/test_sdk_mcp_tools.py +4 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/e2e/test_slash_commands.py +1 -1
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/e2e/test_stderr_callback.py +1 -1
- clawd_code_sdk-0.3.7/tests/e2e/test_subagent_invocation.py +184 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/e2e/test_tool_permissions.py +6 -7
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/mock_claude_server.py +16 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/test_client.py +25 -1
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/test_integration.py +60 -2
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/test_message_parser.py +0 -55
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/test_session.py +29 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/test_streaming_client.py +47 -0
- clawd_code_sdk-0.3.6/tests/e2e/test_subagent_invocation.py +0 -112
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/.gitignore +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/LICENSE +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/README.md +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/__init__.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/_bundled/.gitignore +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/_errors.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/_internal/__init__.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/_internal/message_parser.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/_internal/query.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/_internal/transport/__init__.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/_internal/transport/subprocess_cli.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/_version.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/anthropic_types.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/client.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/list_sessions.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/mcp_utils.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/content_blocks.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/control.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/mcp.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/options.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/permissions.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/sandbox.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/models/server_info.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/py.typed +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/query.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/session.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/storage/ARCHITECTURE.md +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/storage/__init__.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/storage/helpers.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/storage/models.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/storage/replay.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/src/clawd_code_sdk/usage.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/conftest.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/e2e/__init__.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/e2e/test_structured_output.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/mcp_server.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/test_changelog.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/test_errors.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/test_image.png +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/test_sdk_mcp_integration.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/test_subprocess_buffering.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/test_tool_callbacks.py +0 -0
- {clawd_code_sdk-0.3.6 → clawd_code_sdk-0.3.7}/tests/test_transport.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clawd-code-sdk
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Summary: Python SDK for Claude Code
|
|
5
5
|
Project-URL: Documentation, https://github.com/phil65/claude-agent-sdk-python
|
|
6
6
|
Project-URL: Homepage, https://github.com/phil65/claude-agent-sdk-python
|
|
@@ -90,6 +90,7 @@ from .input_types import (
|
|
|
90
90
|
AskUserQuestionOption,
|
|
91
91
|
BashInput,
|
|
92
92
|
BashOutputInput,
|
|
93
|
+
EnterPlanModeInput,
|
|
93
94
|
ExitPlanModeInput,
|
|
94
95
|
FileEditInput,
|
|
95
96
|
FileReadInput,
|
|
@@ -100,6 +101,7 @@ from .input_types import (
|
|
|
100
101
|
ListMcpResourcesInput,
|
|
101
102
|
NotebookEditInput,
|
|
102
103
|
ReadMcpResourceInput,
|
|
104
|
+
SkillInput,
|
|
103
105
|
TodoItem,
|
|
104
106
|
TodoWriteInput,
|
|
105
107
|
ToolInput,
|
|
@@ -141,11 +143,14 @@ from .output_types import (
|
|
|
141
143
|
AskUserQuestionItem,
|
|
142
144
|
AskUserQuestionOutput,
|
|
143
145
|
BashOutput,
|
|
146
|
+
BashOutputOutput,
|
|
144
147
|
BashToolUseResult,
|
|
145
148
|
ConfigOutput,
|
|
146
149
|
EditOutput,
|
|
147
150
|
EditToolUseResult,
|
|
151
|
+
EnterPlanModeOutput,
|
|
148
152
|
EnterWorktreeOutput,
|
|
153
|
+
KillShellOutput,
|
|
149
154
|
ExitPlanModeOutput,
|
|
150
155
|
GitDiff,
|
|
151
156
|
GlobOutput,
|
|
@@ -169,6 +174,7 @@ from .output_types import (
|
|
|
169
174
|
ReadPdfOutput,
|
|
170
175
|
ReadTextOutput,
|
|
171
176
|
ReadToolUseResult,
|
|
177
|
+
SkillOutput,
|
|
172
178
|
StructuredPatchHunk,
|
|
173
179
|
SubscribeMcpResourceOutput,
|
|
174
180
|
SubscribePollingOutput,
|
|
@@ -426,9 +432,11 @@ __all__ = [
|
|
|
426
432
|
"WebSearchInput",
|
|
427
433
|
"TodoItem",
|
|
428
434
|
"TodoWriteInput",
|
|
435
|
+
"EnterPlanModeInput",
|
|
429
436
|
"ExitPlanModeInput",
|
|
430
437
|
"ListMcpResourcesInput",
|
|
431
438
|
"ReadMcpResourceInput",
|
|
439
|
+
"SkillInput",
|
|
432
440
|
# output_types (actual tool_use_result wire format)
|
|
433
441
|
"TOOL_USE_RESULT_TYPES",
|
|
434
442
|
"AgentAsyncLaunchedOutput",
|
|
@@ -442,9 +450,12 @@ __all__ = [
|
|
|
442
450
|
"AskUserQuestionItem",
|
|
443
451
|
"AskUserQuestionOutput",
|
|
444
452
|
"BashOutput",
|
|
453
|
+
"BashOutputOutput",
|
|
445
454
|
"ConfigOutput",
|
|
446
455
|
"EditOutput",
|
|
456
|
+
"EnterPlanModeOutput",
|
|
447
457
|
"EnterWorktreeOutput",
|
|
458
|
+
"KillShellOutput",
|
|
448
459
|
"ExitPlanModeOutput",
|
|
449
460
|
"GitDiff",
|
|
450
461
|
"GlobOutput",
|
|
@@ -467,6 +478,7 @@ __all__ = [
|
|
|
467
478
|
"ReadPdfFileInfo",
|
|
468
479
|
"ReadPdfOutput",
|
|
469
480
|
"ReadTextOutput",
|
|
481
|
+
"SkillOutput",
|
|
470
482
|
"StructuredPatchHunk",
|
|
471
483
|
"SubscribeMcpResourceOutput",
|
|
472
484
|
"SubscribePollingOutput",
|
|
@@ -53,6 +53,7 @@ class AgentDefinition:
|
|
|
53
53
|
critical_system_reminder_experimental: str | None = None
|
|
54
54
|
skills: list[str] | None = None
|
|
55
55
|
max_turns: int | None = None
|
|
56
|
+
background: bool | None = None
|
|
56
57
|
# permission_mode: PermissionMode | None = None
|
|
57
58
|
# hooks: dict[HookEvent, list[HookMatcher]] | None = None
|
|
58
59
|
|
|
@@ -22,6 +22,8 @@ ModelName = Literal["sonnet", "opus", "haiku"]
|
|
|
22
22
|
PermissionBehavior = Literal["allow", "deny", "ask"]
|
|
23
23
|
ReasoningEffort = Literal["low", "medium", "high", "max"]
|
|
24
24
|
TaskStatus = Literal["completed", "failed", "stopped"]
|
|
25
|
+
CompactionTrigger = Literal["auto", "manual"]
|
|
26
|
+
|
|
25
27
|
StopReason = Literal[
|
|
26
28
|
"end_turn",
|
|
27
29
|
"max_tokens",
|
|
@@ -6,6 +6,8 @@ from collections.abc import Awaitable, Callable
|
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
7
|
from typing import TYPE_CHECKING, Any, Literal, NotRequired, TypedDict
|
|
8
8
|
|
|
9
|
+
from clawd_code_sdk.models.base import CompactionTrigger # noqa: TC001
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
if TYPE_CHECKING:
|
|
11
13
|
from collections.abc import Sequence
|
|
@@ -101,7 +103,7 @@ class PreCompactHookInput(BaseHookInput):
|
|
|
101
103
|
"""Input data for PreCompact hook events."""
|
|
102
104
|
|
|
103
105
|
hook_event_name: Literal["PreCompact"]
|
|
104
|
-
trigger:
|
|
106
|
+
trigger: CompactionTrigger
|
|
105
107
|
custom_instructions: str | None
|
|
106
108
|
|
|
107
109
|
|
|
@@ -252,6 +252,29 @@ class EnterWorktreeInput(TypedDict):
|
|
|
252
252
|
"""Optional name for the worktree. A random name is generated if not provided."""
|
|
253
253
|
|
|
254
254
|
|
|
255
|
+
@_extra_allow
|
|
256
|
+
class SkillInput(TypedDict):
|
|
257
|
+
"""Input for the Skill tool. Invokes a named skill (slash command).
|
|
258
|
+
|
|
259
|
+
Not part of the official SDK ToolInputSchemas as of SDK v0.2.62.
|
|
260
|
+
Shape derived from empirical testing.
|
|
261
|
+
"""
|
|
262
|
+
|
|
263
|
+
skill: str
|
|
264
|
+
"""The skill name (e.g., "commit", "review", "debug")."""
|
|
265
|
+
args: NotRequired[str]
|
|
266
|
+
"""Optional arguments for the skill."""
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@_extra_allow
|
|
270
|
+
class EnterPlanModeInput(TypedDict):
|
|
271
|
+
"""Input for the EnterPlanMode tool. Enters planning mode.
|
|
272
|
+
|
|
273
|
+
Not part of the official SDK ToolInputSchemas as of SDK v0.2.62.
|
|
274
|
+
Shape derived from empirical testing.
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
|
|
255
278
|
@_extra_allow
|
|
256
279
|
class ExitPlanModeInput(TypedDict):
|
|
257
280
|
"""Input for the ExitPlanMode tool. Exits planning mode for user approval."""
|
|
@@ -297,6 +320,8 @@ ToolInput = (
|
|
|
297
320
|
| ExitPlanModeInput
|
|
298
321
|
| ListMcpResourcesInput
|
|
299
322
|
| ReadMcpResourceInput
|
|
323
|
+
| SkillInput
|
|
324
|
+
| EnterPlanModeInput
|
|
300
325
|
)
|
|
301
326
|
|
|
302
327
|
#: Mapping from tool name to its input type.
|
|
@@ -319,4 +344,6 @@ TOOL_INPUT_TYPES: dict[str, type[ToolInput]] = {
|
|
|
319
344
|
"ExitPlanMode": ExitPlanModeInput,
|
|
320
345
|
"ListMcpResources": ListMcpResourcesInput,
|
|
321
346
|
"ReadMcpResource": ReadMcpResourceInput,
|
|
347
|
+
"Skill": SkillInput,
|
|
348
|
+
"EnterPlanMode": EnterPlanModeInput,
|
|
322
349
|
}
|
|
@@ -23,7 +23,14 @@ from clawd_code_sdk.models.content_blocks import ContentBlock, TextBlock # noqa
|
|
|
23
23
|
from clawd_code_sdk.models.mcp import McpConnectionStatus # noqa: TC001
|
|
24
24
|
from clawd_code_sdk.models.output_types import ToolUseResult # noqa: TC001
|
|
25
25
|
|
|
26
|
-
from .base import
|
|
26
|
+
from .base import ( # noqa: TC001
|
|
27
|
+
ApiKeySource,
|
|
28
|
+
CompactionTrigger,
|
|
29
|
+
PermissionMode,
|
|
30
|
+
StopReason,
|
|
31
|
+
TaskStatus,
|
|
32
|
+
ToolName,
|
|
33
|
+
)
|
|
27
34
|
|
|
28
35
|
|
|
29
36
|
if TYPE_CHECKING:
|
|
@@ -178,14 +185,14 @@ class InitSystemMessage(BaseSystemMessage):
|
|
|
178
185
|
"""System init message with session metadata."""
|
|
179
186
|
|
|
180
187
|
subtype: Literal["init"] = "init"
|
|
181
|
-
apiKeySource: ApiKeySource | None
|
|
188
|
+
apiKeySource: ApiKeySource | None # noqa: N815
|
|
182
189
|
cwd: str
|
|
183
190
|
tools: list[str]
|
|
184
191
|
mcp_servers: list[McpServerStatus]
|
|
185
192
|
model: Model
|
|
186
193
|
permissionMode: PermissionMode # noqa: N815
|
|
187
194
|
slash_commands: list[str]
|
|
188
|
-
output_style: Literal["default", "json"]
|
|
195
|
+
output_style: Literal["default", "json"] | str
|
|
189
196
|
claude_code_version: str
|
|
190
197
|
agents: list[str]
|
|
191
198
|
skills: list[str]
|
|
@@ -213,7 +220,7 @@ class StatusSystemMessage(BaseSystemMessage):
|
|
|
213
220
|
|
|
214
221
|
|
|
215
222
|
class TriggerMetadata(TypedDict):
|
|
216
|
-
trigger:
|
|
223
|
+
trigger: CompactionTrigger
|
|
217
224
|
pre_tokens: int
|
|
218
225
|
|
|
219
226
|
|
|
@@ -338,21 +345,6 @@ class HookResponseSystemMessage(BaseSystemMessage):
|
|
|
338
345
|
output: str
|
|
339
346
|
|
|
340
347
|
|
|
341
|
-
class CacheCreation(TypedDict):
|
|
342
|
-
ephemeral_1h_input_tokens: int
|
|
343
|
-
ephemeral_5m_input_tokens: int
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
class ServerToolUse(TypedDict):
|
|
347
|
-
web_search_requests: int
|
|
348
|
-
web_fetch_requests: int
|
|
349
|
-
service_tier: Literal["standard", "priority"]
|
|
350
|
-
cache_creation: CacheCreation
|
|
351
|
-
inference_geo: Literal["not_available"] | str
|
|
352
|
-
iterations: list[Any]
|
|
353
|
-
speed: str
|
|
354
|
-
|
|
355
|
-
|
|
356
348
|
class ModelUsage(TypedDict):
|
|
357
349
|
inputTokens: int
|
|
358
350
|
outputTokens: int
|
|
@@ -362,13 +354,12 @@ class ModelUsage(TypedDict):
|
|
|
362
354
|
costUSD: float
|
|
363
355
|
contextWindow: int
|
|
364
356
|
maxOutputTokens: int
|
|
365
|
-
server_tool_use: ServerToolUse
|
|
366
357
|
|
|
367
358
|
|
|
368
359
|
class SDKPermissionDenial(TypedDict):
|
|
369
360
|
tool_name: ToolName | str
|
|
370
361
|
tool_use_id: str
|
|
371
|
-
tool_input: ToolInput
|
|
362
|
+
tool_input: ToolInput | dict[str, Any]
|
|
372
363
|
|
|
373
364
|
|
|
374
365
|
class Usage(TypedDict):
|
|
@@ -391,9 +382,9 @@ class BaseResultMessage(BaseMessage):
|
|
|
391
382
|
num_turns: int
|
|
392
383
|
total_cost_usd: float
|
|
393
384
|
usage: Usage
|
|
394
|
-
stop_reason: StopReason | None
|
|
395
|
-
modelUsage: dict[str, ModelUsage]
|
|
396
|
-
permission_denials: list[SDKPermissionDenial]
|
|
385
|
+
stop_reason: StopReason | None
|
|
386
|
+
modelUsage: dict[str, ModelUsage] # noqa: N815
|
|
387
|
+
permission_denials: list[SDKPermissionDenial]
|
|
397
388
|
|
|
398
389
|
|
|
399
390
|
@dataclass(kw_only=True)
|
|
@@ -94,6 +94,8 @@ class AgentAsyncLaunchedOutput(TypedDict):
|
|
|
94
94
|
|
|
95
95
|
status: Literal["async_launched"]
|
|
96
96
|
"""Indicates the agent was launched in the background."""
|
|
97
|
+
isAsync: Literal[True]
|
|
98
|
+
"""Always True for async-launched agents."""
|
|
97
99
|
agentId: str
|
|
98
100
|
"""The ID of the async agent."""
|
|
99
101
|
description: str
|
|
@@ -165,8 +167,8 @@ class TaskInfo(TypedDict):
|
|
|
165
167
|
"""Information about a background task."""
|
|
166
168
|
|
|
167
169
|
task_id: str
|
|
168
|
-
task_type:
|
|
169
|
-
status:
|
|
170
|
+
task_type: Literal["local_bash", "agent"]
|
|
171
|
+
status: Literal["running", "completed", "failed"]
|
|
170
172
|
description: str
|
|
171
173
|
output: str
|
|
172
174
|
exitCode: int | None
|
|
@@ -175,11 +177,61 @@ class TaskInfo(TypedDict):
|
|
|
175
177
|
class TaskOutputResult(TypedDict):
|
|
176
178
|
"""``tool_use_result`` for the TaskOutput tool (background task polling)."""
|
|
177
179
|
|
|
178
|
-
retrieval_status:
|
|
179
|
-
"""Status of the retrieval
|
|
180
|
+
retrieval_status: Literal["completed", "timeout", "running"]
|
|
181
|
+
"""Status of the retrieval."""
|
|
180
182
|
task: TaskInfo
|
|
181
183
|
|
|
182
184
|
|
|
185
|
+
# ---------------------------------------------------------------------------
|
|
186
|
+
# BashOutput (checking background shells — tool name "BashOutput")
|
|
187
|
+
# ---------------------------------------------------------------------------
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class BashOutputOutput(TypedDict):
|
|
191
|
+
"""``tool_use_result`` for the BashOutput tool (background shell output retrieval).
|
|
192
|
+
|
|
193
|
+
Not part of the official SDK ToolOutputSchemas as of SDK v0.2.62.
|
|
194
|
+
Shape derived from: https://github.com/kzahel/yepanywhere/blob/main/packages/shared/src/claude-sdk-schema/tool/ToolResultSchemas.ts
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
shellId: NotRequired[str]
|
|
198
|
+
"""ID of the background shell."""
|
|
199
|
+
command: NotRequired[str]
|
|
200
|
+
"""The command that was executed."""
|
|
201
|
+
status: NotRequired[Literal["running", "completed", "failed"]]
|
|
202
|
+
"""Current status of the command."""
|
|
203
|
+
exitCode: NotRequired[int | None]
|
|
204
|
+
"""Exit code of the command, or None if still running."""
|
|
205
|
+
stdout: NotRequired[str]
|
|
206
|
+
"""Standard output."""
|
|
207
|
+
stderr: NotRequired[str]
|
|
208
|
+
"""Standard error."""
|
|
209
|
+
stdoutLines: NotRequired[int]
|
|
210
|
+
"""Number of lines in stdout."""
|
|
211
|
+
stderrLines: NotRequired[int]
|
|
212
|
+
"""Number of lines in stderr."""
|
|
213
|
+
timestamp: NotRequired[str]
|
|
214
|
+
"""Timestamp of the output."""
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
# ---------------------------------------------------------------------------
|
|
218
|
+
# KillShell (kill background shell — tool name "KillBash")
|
|
219
|
+
# ---------------------------------------------------------------------------
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class KillShellOutput(TypedDict):
|
|
223
|
+
"""``tool_use_result`` for the KillBash tool.
|
|
224
|
+
|
|
225
|
+
Not part of the official SDK ToolOutputSchemas as of SDK v0.2.62.
|
|
226
|
+
Shape derived from: https://github.com/kzahel/yepanywhere/blob/main/packages/shared/src/claude-sdk-schema/tool/ToolResultSchemas.ts
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
message: NotRequired[str]
|
|
230
|
+
"""Status message."""
|
|
231
|
+
shell_id: NotRequired[str]
|
|
232
|
+
"""ID of the shell that was killed."""
|
|
233
|
+
|
|
234
|
+
|
|
183
235
|
# ---------------------------------------------------------------------------
|
|
184
236
|
# TaskStop
|
|
185
237
|
# ---------------------------------------------------------------------------
|
|
@@ -616,6 +668,42 @@ class ConfigOutput(TypedDict):
|
|
|
616
668
|
"""Error message if the operation failed."""
|
|
617
669
|
|
|
618
670
|
|
|
671
|
+
# ---------------------------------------------------------------------------
|
|
672
|
+
# Skill
|
|
673
|
+
# ---------------------------------------------------------------------------
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
class SkillOutput(TypedDict):
|
|
677
|
+
"""``tool_use_result`` for the Skill tool.
|
|
678
|
+
|
|
679
|
+
Not part of the official SDK ToolOutputSchemas as of SDK v0.2.62.
|
|
680
|
+
Shape derived from empirical testing.
|
|
681
|
+
"""
|
|
682
|
+
|
|
683
|
+
success: bool
|
|
684
|
+
"""Whether the skill was invoked successfully."""
|
|
685
|
+
commandName: str
|
|
686
|
+
"""The name of the skill that was invoked."""
|
|
687
|
+
allowedTools: list[str]
|
|
688
|
+
"""Tools that the skill is allowed to use."""
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
# ---------------------------------------------------------------------------
|
|
692
|
+
# EnterPlanMode
|
|
693
|
+
# ---------------------------------------------------------------------------
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
class EnterPlanModeOutput(TypedDict):
|
|
697
|
+
"""``tool_use_result`` for the EnterPlanMode tool.
|
|
698
|
+
|
|
699
|
+
Not part of the official SDK ToolOutputSchemas as of SDK v0.2.62.
|
|
700
|
+
Shape derived from empirical testing.
|
|
701
|
+
"""
|
|
702
|
+
|
|
703
|
+
message: str
|
|
704
|
+
"""A message indicating that plan mode was entered."""
|
|
705
|
+
|
|
706
|
+
|
|
619
707
|
# ---------------------------------------------------------------------------
|
|
620
708
|
# EnterWorktree
|
|
621
709
|
# ---------------------------------------------------------------------------
|
|
@@ -639,6 +727,8 @@ class EnterWorktreeOutput(TypedDict):
|
|
|
639
727
|
ToolUseResult = (
|
|
640
728
|
AgentOutput
|
|
641
729
|
| BashOutput
|
|
730
|
+
| BashOutputOutput
|
|
731
|
+
| KillShellOutput
|
|
642
732
|
| TaskOutputResult
|
|
643
733
|
| TaskStopOutput
|
|
644
734
|
| ExitPlanModeOutput
|
|
@@ -659,6 +749,8 @@ ToolUseResult = (
|
|
|
659
749
|
| UnsubscribePollingOutput
|
|
660
750
|
| ConfigOutput
|
|
661
751
|
| EnterWorktreeOutput
|
|
752
|
+
| SkillOutput
|
|
753
|
+
| EnterPlanModeOutput
|
|
662
754
|
)
|
|
663
755
|
|
|
664
756
|
#: Backwards-compatible aliases for names previously in ``tool_use_results.py``.
|
|
@@ -674,6 +766,8 @@ TodoWriteToolUseResult = TodoWriteOutput
|
|
|
674
766
|
TOOL_USE_RESULT_TYPES: dict[str, type[Any]] = {
|
|
675
767
|
"Task": AgentCompletedOutput,
|
|
676
768
|
"Bash": BashOutput,
|
|
769
|
+
"BashOutput": BashOutputOutput,
|
|
770
|
+
"KillBash": KillShellOutput,
|
|
677
771
|
"TaskOutput": TaskOutputResult,
|
|
678
772
|
"TaskStop": TaskStopOutput,
|
|
679
773
|
"ExitPlanMode": ExitPlanModeOutput,
|
|
@@ -695,4 +789,6 @@ TOOL_USE_RESULT_TYPES: dict[str, type[Any]] = {
|
|
|
695
789
|
"UnsubscribePolling": UnsubscribePollingOutput,
|
|
696
790
|
"Config": ConfigOutput,
|
|
697
791
|
"EnterWorktree": EnterWorktreeOutput,
|
|
792
|
+
"Skill": SkillOutput,
|
|
793
|
+
"EnterPlanMode": EnterPlanModeOutput,
|
|
698
794
|
}
|
|
@@ -188,7 +188,7 @@ You are a simple test agent. When asked a question, provide a brief, helpful ans
|
|
|
188
188
|
f"Missing AssistantMessage - got only: {message_types}. "
|
|
189
189
|
"This may indicate issue #406 (silent failure with filesystem agents)."
|
|
190
190
|
)
|
|
191
|
-
assert "
|
|
191
|
+
assert "ResultSuccessMessage" in message_types, "Missing ResultMessage"
|
|
192
192
|
|
|
193
193
|
# Find the init message and check for the filesystem agent
|
|
194
194
|
for msg in messages:
|
|
@@ -517,4 +517,4 @@ async def test_agent_definition_with_mcp_servers():
|
|
|
517
517
|
|
|
518
518
|
|
|
519
519
|
if __name__ == "__main__":
|
|
520
|
-
pytest.main([__file__, "-vv"])
|
|
520
|
+
pytest.main([__file__, "-vv", "-m", "e2e"])
|
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
|
|
5
|
-
from clawd_code_sdk import
|
|
6
|
-
ClaudeAgentOptions,
|
|
7
|
-
ClaudeSDKClient,
|
|
8
|
-
)
|
|
5
|
+
from clawd_code_sdk import ClaudeAgentOptions, ClaudeSDKClient
|
|
9
6
|
|
|
10
7
|
|
|
11
8
|
@pytest.mark.e2e
|
|
@@ -13,27 +10,21 @@ from clawd_code_sdk import (
|
|
|
13
10
|
async def test_set_permission_mode():
|
|
14
11
|
"""Test that permission mode can be changed dynamically during a session."""
|
|
15
12
|
|
|
16
|
-
options = ClaudeAgentOptions(
|
|
17
|
-
permission_mode="default",
|
|
18
|
-
)
|
|
13
|
+
options = ClaudeAgentOptions(permission_mode="default")
|
|
19
14
|
|
|
20
15
|
async with ClaudeSDKClient(options=options) as client:
|
|
21
16
|
# Change permission mode to acceptEdits
|
|
22
17
|
await client.set_permission_mode("acceptEdits")
|
|
23
|
-
|
|
24
18
|
# Make a query that would normally require permission
|
|
25
19
|
await client.query("What is 2+2? Just respond with the number.")
|
|
26
|
-
|
|
27
20
|
async for message in client.receive_response():
|
|
28
21
|
print(f"Got message: {message}")
|
|
29
22
|
pass # Just consume messages
|
|
30
23
|
|
|
31
24
|
# Change back to default
|
|
32
25
|
await client.set_permission_mode("default")
|
|
33
|
-
|
|
34
26
|
# Make another query
|
|
35
27
|
await client.query("What is 3+3? Just respond with the number.")
|
|
36
|
-
|
|
37
28
|
async for message in client.receive_response():
|
|
38
29
|
print(f"Got message: {message}")
|
|
39
30
|
pass # Just consume messages
|
|
@@ -43,31 +34,22 @@ async def test_set_permission_mode():
|
|
|
43
34
|
@pytest.mark.asyncio
|
|
44
35
|
async def test_set_model():
|
|
45
36
|
"""Test that model can be changed dynamically during a session."""
|
|
46
|
-
|
|
47
|
-
options = ClaudeAgentOptions()
|
|
48
|
-
|
|
49
|
-
async with ClaudeSDKClient(options=options) as client:
|
|
37
|
+
async with ClaudeSDKClient() as client:
|
|
50
38
|
# Start with default model
|
|
51
39
|
await client.query("What is 1+1? Just the number.")
|
|
52
|
-
|
|
53
40
|
async for message in client.receive_response():
|
|
54
41
|
print(f"Default model response: {message}")
|
|
55
42
|
pass
|
|
56
|
-
|
|
57
43
|
# Switch to Haiku model
|
|
58
|
-
await client.set_model("claude-
|
|
59
|
-
|
|
44
|
+
await client.set_model("claude-haiku-4-5")
|
|
60
45
|
await client.query("What is 2+2? Just the number.")
|
|
61
|
-
|
|
62
46
|
async for message in client.receive_response():
|
|
63
47
|
print(f"Haiku model response: {message}")
|
|
64
48
|
pass
|
|
65
49
|
|
|
66
50
|
# Switch back to default (None means default)
|
|
67
51
|
await client.set_model(None)
|
|
68
|
-
|
|
69
52
|
await client.query("What is 3+3? Just the number.")
|
|
70
|
-
|
|
71
53
|
async for message in client.receive_response():
|
|
72
54
|
print(f"Back to default model: {message}")
|
|
73
55
|
pass
|
|
@@ -78,12 +60,9 @@ async def test_set_model():
|
|
|
78
60
|
async def test_interrupt():
|
|
79
61
|
"""Test that interrupt can be sent during a session."""
|
|
80
62
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
async with ClaudeSDKClient(options=options) as client:
|
|
63
|
+
async with ClaudeSDKClient() as client:
|
|
84
64
|
# Start a query
|
|
85
65
|
await client.query("Count from 1 to 100 slowly.")
|
|
86
|
-
|
|
87
66
|
# Send interrupt (may or may not stop the response depending on timing)
|
|
88
67
|
try:
|
|
89
68
|
await client.interrupt()
|
|
@@ -98,4 +77,4 @@ async def test_interrupt():
|
|
|
98
77
|
|
|
99
78
|
|
|
100
79
|
if __name__ == "__main__":
|
|
101
|
-
pytest.main([__file__, "-vv"])
|
|
80
|
+
pytest.main([__file__, "-vv", "-m", "e2e"])
|
|
@@ -6,6 +6,7 @@ including StreamEvent parsing and message interleaving.
|
|
|
6
6
|
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
+
from anthropic.types import RawContentBlockDeltaEvent, ThinkingDelta
|
|
9
10
|
import pytest
|
|
10
11
|
|
|
11
12
|
from clawd_code_sdk import ClaudeSDKClient
|
|
@@ -18,6 +19,7 @@ from clawd_code_sdk.models import (
|
|
|
18
19
|
TextBlock,
|
|
19
20
|
ThinkingBlock,
|
|
20
21
|
)
|
|
22
|
+
from clawd_code_sdk.models.base import ThinkingConfigEnabled
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
@pytest.mark.e2e
|
|
@@ -55,7 +57,7 @@ async def test_include_partial_messages_stream_events():
|
|
|
55
57
|
assert len(stream_events) > 0, "No StreamEvent messages received"
|
|
56
58
|
|
|
57
59
|
# Check for expected StreamEvent types
|
|
58
|
-
event_types = [event.event.
|
|
60
|
+
event_types = [event.event.type for event in stream_events]
|
|
59
61
|
assert "message_start" in event_types, "No message_start StreamEvent"
|
|
60
62
|
assert "content_block_start" in event_types, "No content_block_start StreamEvent"
|
|
61
63
|
assert "content_block_delta" in event_types, "No content_block_delta StreamEvent"
|
|
@@ -91,9 +93,7 @@ async def test_include_partial_messages_thinking_deltas():
|
|
|
91
93
|
options = ClaudeAgentOptions(
|
|
92
94
|
model="claude-sonnet-4-5",
|
|
93
95
|
max_turns=2,
|
|
94
|
-
|
|
95
|
-
"MAX_THINKING_TOKENS": "8000",
|
|
96
|
-
},
|
|
96
|
+
thinking=ThinkingConfigEnabled(type="enabled", budget_tokens=8000),
|
|
97
97
|
)
|
|
98
98
|
|
|
99
99
|
thinking_deltas = []
|
|
@@ -102,19 +102,22 @@ async def test_include_partial_messages_thinking_deltas():
|
|
|
102
102
|
await client.query("Think step by step about what 2 + 2 equals")
|
|
103
103
|
|
|
104
104
|
async for message in client.receive_response():
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
105
|
+
print(message)
|
|
106
|
+
if (
|
|
107
|
+
isinstance(message, StreamEvent)
|
|
108
|
+
and isinstance(message.event, RawContentBlockDeltaEvent)
|
|
109
|
+
and isinstance(message.event.delta, ThinkingDelta)
|
|
110
|
+
):
|
|
111
|
+
thinking_deltas.append(message.event.delta.thinking)
|
|
111
112
|
|
|
112
113
|
# Should have received multiple thinking deltas
|
|
113
114
|
assert len(thinking_deltas) > 0, "No thinking deltas received"
|
|
114
|
-
|
|
115
115
|
# Combined thinking should form coherent text
|
|
116
116
|
combined_thinking = "".join(thinking_deltas)
|
|
117
117
|
assert len(combined_thinking) > 10, "Thinking content too short"
|
|
118
|
-
|
|
119
118
|
# Should contain some reasoning about the calculation
|
|
120
119
|
assert "2" in combined_thinking.lower(), "Thinking doesn't mention the numbers"
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
if __name__ == "__main__":
|
|
123
|
+
pytest.main([__file__, "-vv", "-m", "e2e"])
|
|
@@ -58,7 +58,7 @@ async def test_mcp_image_tool_wire_format():
|
|
|
58
58
|
# Verify we got a result
|
|
59
59
|
result_messages = [m for m in messages if isinstance(m, ResultMessage)]
|
|
60
60
|
assert result_messages, f"No ResultMessage. Got: {[type(m).__name__ for m in messages]}"
|
|
61
|
-
assert not result_messages[0].is_error
|
|
61
|
+
assert not result_messages[0].is_error
|
|
62
62
|
|
|
63
63
|
# Inspect all content blocks from assistant and user messages
|
|
64
64
|
all_content_blocks: list[dict[str, Any]] = []
|
|
@@ -104,7 +104,7 @@ async def test_mcp_image_tool_wire_format():
|
|
|
104
104
|
assert "source" in image_param
|
|
105
105
|
assert image_param["source"]["type"] == "base64"
|
|
106
106
|
assert image_param["source"]["media_type"] == "image/png"
|
|
107
|
-
assert len(image_param["source"]["data"]) > 0, "Image data should not be empty"
|
|
107
|
+
assert len(image_param["source"]["data"]) > 0, "Image data should not be empty" # pyright: ignore[reportArgumentType]
|
|
108
108
|
|
|
109
109
|
|
|
110
110
|
@pytest.mark.e2e
|
|
@@ -143,7 +143,7 @@ async def test_mcp_progress_tool_wire_format():
|
|
|
143
143
|
# Verify we got a successful result
|
|
144
144
|
result_messages = [m for m in messages if isinstance(m, ResultMessage)]
|
|
145
145
|
assert result_messages, f"No ResultMessage. Got: {[type(m).__name__ for m in messages]}"
|
|
146
|
-
assert not result_messages[0].is_error
|
|
146
|
+
assert not result_messages[0].is_error
|
|
147
147
|
|
|
148
148
|
# Collect assistant content blocks to verify tool_use
|
|
149
149
|
all_content_blocks: list[dict[str, Any]] = []
|