Skip to content

Commit 84edd73

Browse files
dicksontsaiclaude
andauthored
feat: add timeout parameter to HookMatcher (#351)
## Summary - Adds optional `timeout` field to `HookMatcher` dataclass in `types.py` that allows users to specify a custom timeout (in seconds) for hooks - Propagates the timeout value through: - `client.py` and `_internal/client.py`: `_convert_hooks_to_internal()` method - `_internal/query.py`: hook config sent to CLI ## Test plan - [x] Verify hooks work without timeout specified (default behavior) - [x] Verify custom timeout is passed to CLI when specified in HookMatcher 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <[email protected]>
1 parent bf528a1 commit 84edd73

File tree

4 files changed

+16
-8
lines changed

4 files changed

+16
-8
lines changed

src/claude_agent_sdk/_internal/client.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ def _convert_hooks_to_internal_format(
3131
internal_hooks[event] = []
3232
for matcher in matchers:
3333
# Convert HookMatcher to internal dict format
34-
internal_matcher = {
34+
internal_matcher: dict[str, Any] = {
3535
"matcher": matcher.matcher if hasattr(matcher, "matcher") else None,
3636
"hooks": matcher.hooks if hasattr(matcher, "hooks") else [],
3737
}
38+
if hasattr(matcher, "timeout") and matcher.timeout is not None:
39+
internal_matcher["timeout"] = matcher.timeout
3840
internal_hooks[event].append(internal_matcher)
3941
return internal_hooks
4042

src/claude_agent_sdk/_internal/query.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,13 @@ async def initialize(self) -> dict[str, Any] | None:
126126
self.next_callback_id += 1
127127
self.hook_callbacks[callback_id] = callback
128128
callback_ids.append(callback_id)
129-
hooks_config[event].append(
130-
{
131-
"matcher": matcher.get("matcher"),
132-
"hookCallbackIds": callback_ids,
133-
}
134-
)
129+
hook_matcher_config: dict[str, Any] = {
130+
"matcher": matcher.get("matcher"),
131+
"hookCallbackIds": callback_ids,
132+
}
133+
if matcher.get("timeout") is not None:
134+
hook_matcher_config["timeout"] = matcher.get("timeout")
135+
hooks_config[event].append(hook_matcher_config)
135136

136137
# Send initialize request
137138
request = {

src/claude_agent_sdk/client.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,12 @@ def _convert_hooks_to_internal_format(
7575
internal_hooks[event] = []
7676
for matcher in matchers:
7777
# Convert HookMatcher to internal dict format
78-
internal_matcher = {
78+
internal_matcher: dict[str, Any] = {
7979
"matcher": matcher.matcher if hasattr(matcher, "matcher") else None,
8080
"hooks": matcher.hooks if hasattr(matcher, "hooks") else [],
8181
}
82+
if hasattr(matcher, "timeout") and matcher.timeout is not None:
83+
internal_matcher["timeout"] = matcher.timeout
8284
internal_hooks[event].append(internal_matcher)
8385
return internal_hooks
8486

src/claude_agent_sdk/types.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,9 @@ class HookMatcher:
366366
# A list of Python functions with function signature HookCallback
367367
hooks: list[HookCallback] = field(default_factory=list)
368368

369+
# Timeout in seconds for all hooks in this matcher (default: 60)
370+
timeout: int | None = None
371+
369372

370373
# MCP Server config
371374
class McpStdioServerConfig(TypedDict):

0 commit comments

Comments
 (0)