Skip to content

Commit cf6c32e

Browse files
authored
Merge branch 'main' into lorenze/imp/issue-driven-pull-requests
2 parents 66ce0c5 + 7accafb commit cf6c32e

4 files changed

Lines changed: 109 additions & 5 deletions

File tree

.github/dependabot.yml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
1-
# To get started with Dependabot version updates, you'll need to specify which
2-
# package ecosystems to update and where the package manifests are located.
3-
# Please see the documentation for all configuration options:
41
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
52

63
version: 2
74
updates:
85
- package-ecosystem: uv
96
directory: "/"
107
schedule:
11-
interval: "weekly"
8+
interval: weekly
9+
day: monday
10+
open-pull-requests-limit: 10
1211
groups:
1312
security-updates:
1413
applies-to: security-updates
1514
patterns:
1615
- "*"
16+
patch-minor-updates:
17+
applies-to: version-updates
18+
patterns:
19+
- "*"
20+
update-types:
21+
- patch
22+
- minor
23+
ignore:
24+
- dependency-name: "*"
25+
update-types:
26+
- version-update:semver-major

lib/crewai/src/crewai/events/event_listener.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
MethodExecutionPausedEvent,
5555
MethodExecutionStartedEvent,
5656
)
57+
from crewai.events.types.hook_events import HookDispatchedEvent
5758
from crewai.events.types.knowledge_events import (
5859
KnowledgeQueryCompletedEvent,
5960
KnowledgeQueryFailedEvent,
@@ -875,5 +876,12 @@ def on_crew_kickoff_hooks(_: Any, event: CrewKickoffStartedEvent) -> None:
875876
if has_hooks:
876877
self._telemetry.feature_usage_span("hooks:registered")
877878

879+
@crewai_event_bus.on(HookDispatchedEvent)
880+
def on_hook_dispatched(_: Any, event: HookDispatchedEvent) -> None:
881+
self._telemetry.hook_dispatched_span(
882+
interception_point=event.interception_point,
883+
outcome=event.outcome,
884+
)
885+
878886

879887
event_listener = EventListener()

lib/crewai/src/crewai/telemetry/telemetry.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1148,7 +1148,8 @@ def feature_usage_span(self, feature: str) -> None:
11481148
11491149
Args:
11501150
feature: Feature identifier, e.g. "planning:creation",
1151-
"mcp:connection", "a2a:delegation".
1151+
"mcp:connection", "a2a:delegation",
1152+
"hooks:pre_tool_call", "hooks:aborted".
11521153
"""
11531154

11541155
def _operation() -> None:
@@ -1160,6 +1161,21 @@ def _operation() -> None:
11601161

11611162
self._safe_telemetry_operation(_operation)
11621163

1164+
def hook_dispatched_span(
1165+
self,
1166+
interception_point: str,
1167+
outcome: str,
1168+
) -> None:
1169+
"""Records an interception-hook dispatch via Feature Usage.
1170+
1171+
Emits ``hooks:<point>`` on every dispatch, plus ``hooks:aborted`` when
1172+
a hook aborted the operation (e.g. a policy check). No reasons,
1173+
payloads, or other user content are recorded.
1174+
"""
1175+
self.feature_usage_span(f"hooks:{interception_point}")
1176+
if outcome == "aborted":
1177+
self.feature_usage_span("hooks:aborted")
1178+
11631179
def coding_agent_span(self) -> None:
11641180
"""Records which AI coding assistant (if any) is running this process.
11651181

lib/crewai/tests/telemetry/test_telemetry.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,73 @@ def init_in_thread():
230230
mock_holder["logger"].debug.assert_any_call(
231231
"Skipping signal handler registration: not running in main thread"
232232
)
233+
234+
235+
def test_hook_dispatched_span_counts_point_usage():
236+
with (
237+
patch.dict(
238+
os.environ,
239+
{
240+
"CREWAI_DISABLE_TELEMETRY": "false",
241+
"CREWAI_DISABLE_TRACKING": "false",
242+
"OTEL_SDK_DISABLED": "false",
243+
},
244+
),
245+
patch("crewai.telemetry.telemetry.TracerProvider"),
246+
):
247+
telemetry = Telemetry()
248+
with patch.object(telemetry, "feature_usage_span") as feature_usage_span:
249+
telemetry.hook_dispatched_span("pre_tool_call", "proceeded")
250+
251+
feature_usage_span.assert_called_once_with("hooks:pre_tool_call")
252+
253+
254+
def test_hook_dispatched_span_counts_aborts():
255+
with (
256+
patch.dict(
257+
os.environ,
258+
{
259+
"CREWAI_DISABLE_TELEMETRY": "false",
260+
"CREWAI_DISABLE_TRACKING": "false",
261+
"OTEL_SDK_DISABLED": "false",
262+
},
263+
),
264+
patch("crewai.telemetry.telemetry.TracerProvider"),
265+
):
266+
telemetry = Telemetry()
267+
with patch.object(telemetry, "feature_usage_span") as feature_usage_span:
268+
telemetry.hook_dispatched_span("pre_tool_call", "aborted")
269+
270+
feature_usage_span.assert_any_call("hooks:pre_tool_call")
271+
feature_usage_span.assert_any_call("hooks:aborted")
272+
assert feature_usage_span.call_count == 2
273+
274+
275+
def test_event_listener_tracks_hook_dispatched_events():
276+
from crewai.events.event_bus import crewai_event_bus
277+
from crewai.events.event_listener import event_listener
278+
from crewai.events.types.hook_events import HookDispatchedEvent
279+
280+
with (
281+
crewai_event_bus.scoped_handlers(),
282+
patch.object(
283+
event_listener._telemetry,
284+
"hook_dispatched_span",
285+
) as hook_dispatched_span,
286+
):
287+
event_listener.setup_listeners(crewai_event_bus)
288+
crewai_event_bus.emit(
289+
"test",
290+
HookDispatchedEvent(
291+
interception_point="pre_tool_call",
292+
outcome="aborted",
293+
hook_count=1,
294+
duration_ms=1.5,
295+
),
296+
)
297+
crewai_event_bus.flush()
298+
299+
hook_dispatched_span.assert_called_once_with(
300+
interception_point="pre_tool_call",
301+
outcome="aborted",
302+
)

0 commit comments

Comments
 (0)