mojentic 0.5.7__py3-none-any.whl → 0.6.1__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.
- _examples/recursive_agent.py +4 -3
- _examples/tracer_demo.py +170 -0
- mojentic/agents/simple_recursive_agent.py +20 -21
- mojentic/dispatcher.py +17 -1
- mojentic/llm/gateways/openai_message_adapter_spec.py +7 -7
- mojentic/llm/gateways/openai_messages_adapter.py +58 -15
- mojentic/llm/llm_broker.py +97 -4
- mojentic/llm/message_composers_spec.py +43 -25
- mojentic/llm/tools/llm_tool.py +28 -1
- mojentic/llm/tools/llm_tool_spec.py +2 -1
- mojentic/tracer/__init__.py +16 -0
- mojentic/tracer/event_store.py +111 -0
- mojentic/tracer/event_store_spec.py +210 -0
- mojentic/tracer/null_tracer.py +203 -0
- mojentic/tracer/tracer_events.py +138 -0
- mojentic/tracer/tracer_events_spec.py +116 -0
- mojentic/tracer/tracer_system.py +301 -0
- mojentic/tracer/tracer_system_spec.py +266 -0
- {mojentic-0.5.7.dist-info → mojentic-0.6.1.dist-info}/METADATA +20 -10
- {mojentic-0.5.7.dist-info → mojentic-0.6.1.dist-info}/RECORD +23 -16
- {mojentic-0.5.7.dist-info → mojentic-0.6.1.dist-info}/WHEEL +1 -1
- mojentic/audit/event_store.py +0 -6
- mojentic/audit/event_store_spec.py +0 -26
- {mojentic-0.5.7.dist-info → mojentic-0.6.1.dist-info}/licenses/LICENSE.md +0 -0
- {mojentic-0.5.7.dist-info → mojentic-0.6.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Defines tracer event types for tracking system interactions.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Any, Dict, List, Optional, Type
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
import uuid
|
|
7
|
+
|
|
8
|
+
from pydantic import Field
|
|
9
|
+
|
|
10
|
+
from mojentic.event import Event
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TracerEvent(Event):
|
|
14
|
+
"""
|
|
15
|
+
Base class for all tracer-specific events.
|
|
16
|
+
|
|
17
|
+
Tracer events are used to track system interactions for observability purposes.
|
|
18
|
+
They are distinct from regular events which are used for agent communication.
|
|
19
|
+
"""
|
|
20
|
+
timestamp: float = Field(..., description="Timestamp when the event occurred")
|
|
21
|
+
correlation_id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="UUID string that is copied from cause-to-affect for tracing events")
|
|
22
|
+
|
|
23
|
+
def printable_summary(self) -> str:
|
|
24
|
+
"""
|
|
25
|
+
Return a formatted string summary of the event.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
str
|
|
30
|
+
A formatted string with the event information.
|
|
31
|
+
"""
|
|
32
|
+
event_time = datetime.fromtimestamp(self.timestamp).strftime("%H:%M:%S.%f")[:-3]
|
|
33
|
+
return f"[{event_time}] {type(self).__name__} (correlation_id: {self.correlation_id})"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class LLMCallTracerEvent(TracerEvent):
|
|
37
|
+
"""
|
|
38
|
+
Records when an LLM is called with specific messages.
|
|
39
|
+
"""
|
|
40
|
+
model: str = Field(..., description="The LLM model that was used")
|
|
41
|
+
messages: List[dict] = Field(..., description="The messages sent to the LLM")
|
|
42
|
+
temperature: float = Field(1.0, description="The temperature setting used for the call")
|
|
43
|
+
tools: Optional[List[Dict]] = Field(None, description="The tools available to the LLM, if any")
|
|
44
|
+
|
|
45
|
+
def printable_summary(self) -> str:
|
|
46
|
+
"""Return a formatted summary of the LLM call event."""
|
|
47
|
+
base_summary = super().printable_summary()
|
|
48
|
+
summary = f"{base_summary}\n Model: {self.model}"
|
|
49
|
+
|
|
50
|
+
if self.messages:
|
|
51
|
+
msg_count = len(self.messages)
|
|
52
|
+
summary += f"\n Messages: {msg_count} message{'s' if msg_count != 1 else ''}"
|
|
53
|
+
|
|
54
|
+
if self.temperature != 1.0:
|
|
55
|
+
summary += f"\n Temperature: {self.temperature}"
|
|
56
|
+
|
|
57
|
+
if self.tools:
|
|
58
|
+
tool_names = [tool.get('name', 'unknown') for tool in self.tools]
|
|
59
|
+
summary += f"\n Available Tools: {', '.join(tool_names)}"
|
|
60
|
+
|
|
61
|
+
return summary
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class LLMResponseTracerEvent(TracerEvent):
|
|
65
|
+
"""
|
|
66
|
+
Records when an LLM responds to a call.
|
|
67
|
+
"""
|
|
68
|
+
model: str = Field(..., description="The LLM model that was used")
|
|
69
|
+
content: str = Field(..., description="The content of the LLM response")
|
|
70
|
+
tool_calls: Optional[List[Dict]] = Field(None, description="Any tool calls made by the LLM")
|
|
71
|
+
call_duration_ms: Optional[float] = Field(None, description="Duration of the LLM call in milliseconds")
|
|
72
|
+
|
|
73
|
+
def printable_summary(self) -> str:
|
|
74
|
+
"""Return a formatted summary of the LLM response event."""
|
|
75
|
+
base_summary = super().printable_summary()
|
|
76
|
+
summary = f"{base_summary}\n Model: {self.model}"
|
|
77
|
+
|
|
78
|
+
if self.content:
|
|
79
|
+
content_preview = self.content[:100] + "..." if len(self.content) > 100 else self.content
|
|
80
|
+
summary += f"\n Content: {content_preview}"
|
|
81
|
+
|
|
82
|
+
if self.tool_calls:
|
|
83
|
+
tool_count = len(self.tool_calls)
|
|
84
|
+
summary += f"\n Tool Calls: {tool_count} call{'s' if tool_count != 1 else ''}"
|
|
85
|
+
|
|
86
|
+
if self.call_duration_ms is not None:
|
|
87
|
+
summary += f"\n Duration: {self.call_duration_ms:.2f}ms"
|
|
88
|
+
|
|
89
|
+
return summary
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class ToolCallTracerEvent(TracerEvent):
|
|
93
|
+
"""
|
|
94
|
+
Records when a tool is called during agent execution.
|
|
95
|
+
"""
|
|
96
|
+
tool_name: str = Field(..., description="Name of the tool that was called")
|
|
97
|
+
arguments: Dict[str, Any] = Field(..., description="Arguments provided to the tool")
|
|
98
|
+
result: Any = Field(..., description="Result returned by the tool")
|
|
99
|
+
caller: Optional[str] = Field(None, description="Name of the agent or component that called the tool")
|
|
100
|
+
|
|
101
|
+
def printable_summary(self) -> str:
|
|
102
|
+
"""Return a formatted summary of the tool call event."""
|
|
103
|
+
base_summary = super().printable_summary()
|
|
104
|
+
summary = f"{base_summary}\n Tool: {self.tool_name}"
|
|
105
|
+
|
|
106
|
+
if self.arguments:
|
|
107
|
+
summary += f"\n Arguments: {self.arguments}"
|
|
108
|
+
|
|
109
|
+
if self.result is not None:
|
|
110
|
+
result_str = str(self.result)
|
|
111
|
+
result_preview = result_str[:100] + "..." if len(result_str) > 100 else result_str
|
|
112
|
+
summary += f"\n Result: {result_preview}"
|
|
113
|
+
|
|
114
|
+
if self.caller:
|
|
115
|
+
summary += f"\n Caller: {self.caller}"
|
|
116
|
+
|
|
117
|
+
return summary
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class AgentInteractionTracerEvent(TracerEvent):
|
|
121
|
+
"""
|
|
122
|
+
Records interactions between agents.
|
|
123
|
+
"""
|
|
124
|
+
from_agent: str = Field(..., description="Name of the agent sending the event")
|
|
125
|
+
to_agent: str = Field(..., description="Name of the agent receiving the event")
|
|
126
|
+
event_type: str = Field(..., description="Type of event being processed")
|
|
127
|
+
event_id: Optional[str] = Field(None, description="Unique identifier for the event")
|
|
128
|
+
|
|
129
|
+
def printable_summary(self) -> str:
|
|
130
|
+
"""Return a formatted summary of the agent interaction event."""
|
|
131
|
+
base_summary = super().printable_summary()
|
|
132
|
+
summary = f"{base_summary}\n From: {self.from_agent} → To: {self.to_agent}"
|
|
133
|
+
summary += f"\n Event Type: {self.event_type}"
|
|
134
|
+
|
|
135
|
+
if self.event_id:
|
|
136
|
+
summary += f"\n Event ID: {self.event_id}"
|
|
137
|
+
|
|
138
|
+
return summary
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from typing import Dict, List
|
|
3
|
+
|
|
4
|
+
from mojentic.tracer.tracer_events import (
|
|
5
|
+
TracerEvent,
|
|
6
|
+
LLMCallTracerEvent,
|
|
7
|
+
LLMResponseTracerEvent,
|
|
8
|
+
ToolCallTracerEvent,
|
|
9
|
+
AgentInteractionTracerEvent
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DescribeTracerEvents:
|
|
14
|
+
"""
|
|
15
|
+
Test the tracer event classes to ensure they can be instantiated and have the required properties.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def should_create_base_tracer_event(self):
|
|
19
|
+
"""
|
|
20
|
+
Test creating a base tracer event.
|
|
21
|
+
"""
|
|
22
|
+
# Given / When
|
|
23
|
+
event = TracerEvent(
|
|
24
|
+
source=DescribeTracerEvents,
|
|
25
|
+
timestamp=time.time()
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# Then
|
|
29
|
+
assert isinstance(event, TracerEvent)
|
|
30
|
+
assert isinstance(event.timestamp, float)
|
|
31
|
+
assert event.source == DescribeTracerEvents
|
|
32
|
+
|
|
33
|
+
def should_create_llm_call_tracer_event(self):
|
|
34
|
+
"""
|
|
35
|
+
Test creating an LLM call tracer event.
|
|
36
|
+
"""
|
|
37
|
+
# Given / When
|
|
38
|
+
messages = [{"role": "system", "content": "You are a helpful assistant"}]
|
|
39
|
+
event = LLMCallTracerEvent(
|
|
40
|
+
source=DescribeTracerEvents,
|
|
41
|
+
timestamp=time.time(),
|
|
42
|
+
model="test-model",
|
|
43
|
+
messages=messages,
|
|
44
|
+
temperature=0.7,
|
|
45
|
+
tools=None
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Then
|
|
49
|
+
assert isinstance(event, LLMCallTracerEvent)
|
|
50
|
+
assert event.model == "test-model"
|
|
51
|
+
assert event.messages == messages
|
|
52
|
+
assert event.temperature == 0.7
|
|
53
|
+
assert event.tools is None
|
|
54
|
+
|
|
55
|
+
def should_create_llm_response_tracer_event(self):
|
|
56
|
+
"""
|
|
57
|
+
Test creating an LLM response tracer event.
|
|
58
|
+
"""
|
|
59
|
+
# Given / When
|
|
60
|
+
event = LLMResponseTracerEvent(
|
|
61
|
+
source=DescribeTracerEvents,
|
|
62
|
+
timestamp=time.time(),
|
|
63
|
+
model="test-model",
|
|
64
|
+
content="This is a test response",
|
|
65
|
+
call_duration_ms=150.5
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Then
|
|
69
|
+
assert isinstance(event, LLMResponseTracerEvent)
|
|
70
|
+
assert event.model == "test-model"
|
|
71
|
+
assert event.content == "This is a test response"
|
|
72
|
+
assert event.call_duration_ms == 150.5
|
|
73
|
+
assert event.tool_calls is None
|
|
74
|
+
|
|
75
|
+
def should_create_tool_call_tracer_event(self):
|
|
76
|
+
"""
|
|
77
|
+
Test creating a tool call tracer event.
|
|
78
|
+
"""
|
|
79
|
+
# Given / When
|
|
80
|
+
arguments = {"query": "test query"}
|
|
81
|
+
event = ToolCallTracerEvent(
|
|
82
|
+
source=DescribeTracerEvents,
|
|
83
|
+
timestamp=time.time(),
|
|
84
|
+
tool_name="test-tool",
|
|
85
|
+
arguments=arguments,
|
|
86
|
+
result="test result",
|
|
87
|
+
caller="TestAgent"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Then
|
|
91
|
+
assert isinstance(event, ToolCallTracerEvent)
|
|
92
|
+
assert event.tool_name == "test-tool"
|
|
93
|
+
assert event.arguments == arguments
|
|
94
|
+
assert event.result == "test result"
|
|
95
|
+
assert event.caller == "TestAgent"
|
|
96
|
+
|
|
97
|
+
def should_create_agent_interaction_tracer_event(self):
|
|
98
|
+
"""
|
|
99
|
+
Test creating an agent interaction tracer event.
|
|
100
|
+
"""
|
|
101
|
+
# Given / When
|
|
102
|
+
event = AgentInteractionTracerEvent(
|
|
103
|
+
source=DescribeTracerEvents,
|
|
104
|
+
timestamp=time.time(),
|
|
105
|
+
from_agent="AgentA",
|
|
106
|
+
to_agent="AgentB",
|
|
107
|
+
event_type="RequestEvent",
|
|
108
|
+
event_id="12345"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# Then
|
|
112
|
+
assert isinstance(event, AgentInteractionTracerEvent)
|
|
113
|
+
assert event.from_agent == "AgentA"
|
|
114
|
+
assert event.to_agent == "AgentB"
|
|
115
|
+
assert event.event_type == "RequestEvent"
|
|
116
|
+
assert event.event_id == "12345"
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TracerSystem module for coordinating tracer events.
|
|
3
|
+
|
|
4
|
+
This provides a central system for recording, filtering, and querying tracer events.
|
|
5
|
+
"""
|
|
6
|
+
import time
|
|
7
|
+
from typing import Any, Callable, Dict, List, Optional, Type, Union
|
|
8
|
+
|
|
9
|
+
import structlog
|
|
10
|
+
|
|
11
|
+
from mojentic.tracer.tracer_events import (
|
|
12
|
+
TracerEvent,
|
|
13
|
+
LLMCallTracerEvent,
|
|
14
|
+
LLMResponseTracerEvent,
|
|
15
|
+
ToolCallTracerEvent,
|
|
16
|
+
AgentInteractionTracerEvent
|
|
17
|
+
)
|
|
18
|
+
from mojentic.tracer.event_store import EventStore
|
|
19
|
+
from mojentic.event import Event
|
|
20
|
+
|
|
21
|
+
logger = structlog.get_logger()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TracerSystem:
|
|
25
|
+
"""
|
|
26
|
+
Central system for capturing and querying tracer events.
|
|
27
|
+
|
|
28
|
+
The TracerSystem is responsible for recording events related to LLM calls,
|
|
29
|
+
tool usage, and agent interactions, providing a way to trace through the
|
|
30
|
+
major events of the system.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, event_store: Optional[EventStore] = None, enabled: bool = True):
|
|
34
|
+
"""
|
|
35
|
+
Initialize the tracer system.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
event_store : EventStore, optional
|
|
40
|
+
The event store to use for storing events. If None, a new EventStore will be created.
|
|
41
|
+
enabled : bool, default=True
|
|
42
|
+
Whether the tracer system is enabled. If False, no events will be recorded.
|
|
43
|
+
"""
|
|
44
|
+
self.event_store = event_store or EventStore()
|
|
45
|
+
self.enabled = enabled
|
|
46
|
+
|
|
47
|
+
def record_event(self, event: TracerEvent) -> None:
|
|
48
|
+
"""
|
|
49
|
+
Record a tracer event in the event store.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
event : TracerEvent
|
|
54
|
+
The tracer event to record.
|
|
55
|
+
"""
|
|
56
|
+
if not self.enabled:
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
self.event_store.store(event)
|
|
60
|
+
|
|
61
|
+
def record_llm_call(self,
|
|
62
|
+
model: str,
|
|
63
|
+
messages: List[Dict],
|
|
64
|
+
temperature: float = 1.0,
|
|
65
|
+
tools: Optional[List[Dict]] = None,
|
|
66
|
+
source: Any = None,
|
|
67
|
+
correlation_id: str = None) -> None:
|
|
68
|
+
"""
|
|
69
|
+
Record an LLM call event.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
model : str
|
|
74
|
+
The name of the LLM model being called.
|
|
75
|
+
messages : List[Dict]
|
|
76
|
+
The messages sent to the LLM.
|
|
77
|
+
temperature : float, default=1.0
|
|
78
|
+
The temperature setting for the LLM call.
|
|
79
|
+
tools : List[Dict], optional
|
|
80
|
+
The tools available to the LLM, if any.
|
|
81
|
+
source : Any, optional
|
|
82
|
+
The source of the event. If None, the TracerSystem class will be used.
|
|
83
|
+
correlation_id : str, required
|
|
84
|
+
UUID string that is copied from cause-to-affect for tracing events.
|
|
85
|
+
"""
|
|
86
|
+
if not self.enabled:
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
event = LLMCallTracerEvent(
|
|
90
|
+
source=source or type(self),
|
|
91
|
+
timestamp=time.time(),
|
|
92
|
+
model=model,
|
|
93
|
+
messages=messages,
|
|
94
|
+
temperature=temperature,
|
|
95
|
+
tools=tools,
|
|
96
|
+
correlation_id=correlation_id
|
|
97
|
+
)
|
|
98
|
+
self.event_store.store(event)
|
|
99
|
+
|
|
100
|
+
def record_llm_response(self,
|
|
101
|
+
model: str,
|
|
102
|
+
content: str,
|
|
103
|
+
tool_calls: Optional[List[Dict]] = None,
|
|
104
|
+
call_duration_ms: Optional[float] = None,
|
|
105
|
+
source: Any = None,
|
|
106
|
+
correlation_id: str = None) -> None:
|
|
107
|
+
"""
|
|
108
|
+
Record an LLM response event.
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
model : str
|
|
113
|
+
The name of the LLM model that responded.
|
|
114
|
+
content : str
|
|
115
|
+
The content of the LLM response.
|
|
116
|
+
tool_calls : List[Dict], optional
|
|
117
|
+
Any tool calls made by the LLM in its response.
|
|
118
|
+
call_duration_ms : float, optional
|
|
119
|
+
The duration of the LLM call in milliseconds.
|
|
120
|
+
source : Any, optional
|
|
121
|
+
The source of the event. If None, the TracerSystem class will be used.
|
|
122
|
+
correlation_id : str, required
|
|
123
|
+
UUID string that is copied from cause-to-affect for tracing events.
|
|
124
|
+
"""
|
|
125
|
+
if not self.enabled:
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
event = LLMResponseTracerEvent(
|
|
129
|
+
source=source or type(self),
|
|
130
|
+
timestamp=time.time(),
|
|
131
|
+
model=model,
|
|
132
|
+
content=content,
|
|
133
|
+
tool_calls=tool_calls,
|
|
134
|
+
call_duration_ms=call_duration_ms,
|
|
135
|
+
correlation_id=correlation_id
|
|
136
|
+
)
|
|
137
|
+
self.event_store.store(event)
|
|
138
|
+
|
|
139
|
+
def record_tool_call(self,
|
|
140
|
+
tool_name: str,
|
|
141
|
+
arguments: Dict[str, Any],
|
|
142
|
+
result: Any,
|
|
143
|
+
caller: Optional[str] = None,
|
|
144
|
+
source: Any = None,
|
|
145
|
+
correlation_id: str = None) -> None:
|
|
146
|
+
"""
|
|
147
|
+
Record a tool call event.
|
|
148
|
+
|
|
149
|
+
Parameters
|
|
150
|
+
----------
|
|
151
|
+
tool_name : str
|
|
152
|
+
The name of the tool being called.
|
|
153
|
+
arguments : Dict[str, Any]
|
|
154
|
+
The arguments provided to the tool.
|
|
155
|
+
result : Any
|
|
156
|
+
The result returned by the tool.
|
|
157
|
+
caller : str, optional
|
|
158
|
+
The name of the agent or component calling the tool.
|
|
159
|
+
source : Any, optional
|
|
160
|
+
The source of the event. If None, the TracerSystem class will be used.
|
|
161
|
+
correlation_id : str, required
|
|
162
|
+
UUID string that is copied from cause-to-affect for tracing events.
|
|
163
|
+
"""
|
|
164
|
+
if not self.enabled:
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
event = ToolCallTracerEvent(
|
|
168
|
+
source=source or type(self),
|
|
169
|
+
timestamp=time.time(),
|
|
170
|
+
tool_name=tool_name,
|
|
171
|
+
arguments=arguments,
|
|
172
|
+
result=result,
|
|
173
|
+
caller=caller,
|
|
174
|
+
correlation_id=correlation_id
|
|
175
|
+
)
|
|
176
|
+
self.event_store.store(event)
|
|
177
|
+
|
|
178
|
+
def record_agent_interaction(self,
|
|
179
|
+
from_agent: str,
|
|
180
|
+
to_agent: str,
|
|
181
|
+
event_type: str,
|
|
182
|
+
event_id: Optional[str] = None,
|
|
183
|
+
source: Any = None,
|
|
184
|
+
correlation_id: str = None) -> None:
|
|
185
|
+
"""
|
|
186
|
+
Record an agent interaction event.
|
|
187
|
+
|
|
188
|
+
Parameters
|
|
189
|
+
----------
|
|
190
|
+
from_agent : str
|
|
191
|
+
The name of the agent sending the event.
|
|
192
|
+
to_agent : str
|
|
193
|
+
The name of the agent receiving the event.
|
|
194
|
+
event_type : str
|
|
195
|
+
The type of event being processed.
|
|
196
|
+
event_id : str, optional
|
|
197
|
+
A unique identifier for the event.
|
|
198
|
+
source : Any, optional
|
|
199
|
+
The source of the event. If None, the TracerSystem class will be used.
|
|
200
|
+
correlation_id : str, required
|
|
201
|
+
UUID string that is copied from cause-to-affect for tracing events.
|
|
202
|
+
"""
|
|
203
|
+
if not self.enabled:
|
|
204
|
+
return
|
|
205
|
+
|
|
206
|
+
event = AgentInteractionTracerEvent(
|
|
207
|
+
source=source or type(self),
|
|
208
|
+
timestamp=time.time(),
|
|
209
|
+
from_agent=from_agent,
|
|
210
|
+
to_agent=to_agent,
|
|
211
|
+
event_type=event_type,
|
|
212
|
+
event_id=event_id,
|
|
213
|
+
correlation_id=correlation_id
|
|
214
|
+
)
|
|
215
|
+
self.event_store.store(event)
|
|
216
|
+
|
|
217
|
+
def get_events(self,
|
|
218
|
+
event_type: Optional[Type[TracerEvent]] = None,
|
|
219
|
+
start_time: Optional[float] = None,
|
|
220
|
+
end_time: Optional[float] = None,
|
|
221
|
+
filter_func: Optional[Callable[[TracerEvent], bool]] = None) -> List[TracerEvent]:
|
|
222
|
+
"""
|
|
223
|
+
Get tracer events from the store, optionally filtered.
|
|
224
|
+
|
|
225
|
+
This is a convenience wrapper around the EventStore's get_events method,
|
|
226
|
+
specifically for tracer events.
|
|
227
|
+
|
|
228
|
+
Parameters
|
|
229
|
+
----------
|
|
230
|
+
event_type : Type[TracerEvent], optional
|
|
231
|
+
Filter events by this specific tracer event type.
|
|
232
|
+
start_time : float, optional
|
|
233
|
+
Include events with timestamp >= start_time.
|
|
234
|
+
end_time : float, optional
|
|
235
|
+
Include events with timestamp <= end_time.
|
|
236
|
+
filter_func : Callable[[TracerEvent], bool], optional
|
|
237
|
+
Custom filter function to apply to events.
|
|
238
|
+
|
|
239
|
+
Returns
|
|
240
|
+
-------
|
|
241
|
+
List[TracerEvent]
|
|
242
|
+
Events that match the filter criteria.
|
|
243
|
+
"""
|
|
244
|
+
# First filter to only TracerEvents
|
|
245
|
+
events = self.event_store.get_events(event_type=TracerEvent)
|
|
246
|
+
|
|
247
|
+
# Then apply additional filters
|
|
248
|
+
if event_type is not None:
|
|
249
|
+
events = [e for e in events if isinstance(e, event_type)]
|
|
250
|
+
|
|
251
|
+
if start_time is not None:
|
|
252
|
+
events = [e for e in events if e.timestamp >= start_time]
|
|
253
|
+
|
|
254
|
+
if end_time is not None:
|
|
255
|
+
events = [e for e in events if e.timestamp <= end_time]
|
|
256
|
+
|
|
257
|
+
if filter_func is not None:
|
|
258
|
+
events = [e for e in events if filter_func(e)]
|
|
259
|
+
|
|
260
|
+
return events
|
|
261
|
+
|
|
262
|
+
def get_last_n_tracer_events(self, n: int, event_type: Optional[Type[TracerEvent]] = None) -> List[TracerEvent]:
|
|
263
|
+
"""
|
|
264
|
+
Get the last N tracer events, optionally filtered by type.
|
|
265
|
+
|
|
266
|
+
Parameters
|
|
267
|
+
----------
|
|
268
|
+
n : int
|
|
269
|
+
Number of events to return.
|
|
270
|
+
event_type : Type[TracerEvent], optional
|
|
271
|
+
Filter events by this specific tracer event type.
|
|
272
|
+
|
|
273
|
+
Returns
|
|
274
|
+
-------
|
|
275
|
+
List[TracerEvent]
|
|
276
|
+
The last N tracer events that match the filter criteria.
|
|
277
|
+
"""
|
|
278
|
+
base_type = event_type or TracerEvent
|
|
279
|
+
return self.event_store.get_last_n_events(n, event_type=base_type)
|
|
280
|
+
|
|
281
|
+
def clear(self) -> None:
|
|
282
|
+
"""
|
|
283
|
+
Clear all events from the event store.
|
|
284
|
+
"""
|
|
285
|
+
self.event_store.clear()
|
|
286
|
+
|
|
287
|
+
def enable(self) -> None:
|
|
288
|
+
"""
|
|
289
|
+
Enable the tracer system.
|
|
290
|
+
"""
|
|
291
|
+
self.enabled = True
|
|
292
|
+
|
|
293
|
+
def disable(self) -> None:
|
|
294
|
+
"""
|
|
295
|
+
Disable the tracer system.
|
|
296
|
+
"""
|
|
297
|
+
self.enabled = False
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
# Import and use the null tracer directly in client code via:
|
|
301
|
+
# from mojentic.tracer import null_tracer
|