dacp 0.3.1__py3-none-any.whl → 0.3.2__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.
- dacp/__init__.py +3 -5
- dacp/intelligence.py +230 -305
- dacp/llm.py +13 -6
- dacp/logging_config.py +17 -16
- dacp/main.py +7 -13
- dacp/orchestrator.py +218 -182
- dacp/tools.py +64 -45
- {dacp-0.3.1.dist-info → dacp-0.3.2.dist-info}/METADATA +342 -1
- dacp-0.3.2.dist-info/RECORD +15 -0
- dacp-0.3.1.dist-info/RECORD +0 -15
- {dacp-0.3.1.dist-info → dacp-0.3.2.dist-info}/WHEEL +0 -0
- {dacp-0.3.1.dist-info → dacp-0.3.2.dist-info}/licenses/LICENSE +0 -0
- {dacp-0.3.1.dist-info → dacp-0.3.2.dist-info}/top_level.txt +0 -0
dacp/llm.py
CHANGED
@@ -9,13 +9,13 @@ from .intelligence import invoke_intelligence
|
|
9
9
|
|
10
10
|
def call_llm(prompt: str, model: str = "gpt-4") -> str:
|
11
11
|
"""
|
12
|
-
Legacy function for calling LLMs.
|
12
|
+
Legacy function for calling LLMs.
|
13
13
|
Maintained for backward compatibility.
|
14
|
-
|
14
|
+
|
15
15
|
Args:
|
16
16
|
prompt: The input prompt
|
17
17
|
model: The model to use (defaults to gpt-4)
|
18
|
-
|
18
|
+
|
19
19
|
Returns:
|
20
20
|
Response from the LLM
|
21
21
|
"""
|
@@ -26,7 +26,14 @@ def call_llm(prompt: str, model: str = "gpt-4") -> str:
|
|
26
26
|
"api_key": os.getenv("OPENAI_API_KEY"),
|
27
27
|
"endpoint": "https://api.openai.com/v1",
|
28
28
|
"temperature": 0.7,
|
29
|
-
"max_tokens": 150
|
29
|
+
"max_tokens": 150,
|
30
30
|
}
|
31
|
-
|
32
|
-
|
31
|
+
|
32
|
+
result = invoke_intelligence(prompt, config)
|
33
|
+
|
34
|
+
# Ensure we return a string for backward compatibility
|
35
|
+
if isinstance(result, str):
|
36
|
+
return result
|
37
|
+
else:
|
38
|
+
# If it's a dict (error response), convert to string
|
39
|
+
return str(result.get("error", "Unknown error occurred"))
|
dacp/logging_config.py
CHANGED
@@ -13,11 +13,11 @@ def setup_dacp_logging(
|
|
13
13
|
level: str = "INFO",
|
14
14
|
format_style: str = "detailed",
|
15
15
|
include_timestamp: bool = True,
|
16
|
-
log_file: Optional[str] = None
|
16
|
+
log_file: Optional[str] = None,
|
17
17
|
) -> None:
|
18
18
|
"""
|
19
19
|
Set up logging for DACP components.
|
20
|
-
|
20
|
+
|
21
21
|
Args:
|
22
22
|
level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
23
23
|
format_style: Log format style ('simple', 'detailed', 'emoji')
|
@@ -32,7 +32,9 @@ def setup_dacp_logging(
|
|
32
32
|
log_format = "%(name)s - %(levelname)s - %(message)s"
|
33
33
|
elif format_style == "detailed":
|
34
34
|
if include_timestamp:
|
35
|
-
log_format =
|
35
|
+
log_format = (
|
36
|
+
"%(asctime)s - %(name)s:%(lineno)d - %(levelname)s - %(message)s"
|
37
|
+
)
|
36
38
|
else:
|
37
39
|
log_format = "%(name)s:%(lineno)d - %(levelname)s - %(message)s"
|
38
40
|
elif format_style == "emoji":
|
@@ -43,42 +45,41 @@ def setup_dacp_logging(
|
|
43
45
|
log_format = "%(message)s"
|
44
46
|
else:
|
45
47
|
raise ValueError(f"Unknown format_style: {format_style}")
|
46
|
-
|
48
|
+
|
47
49
|
# Configure root logger for DACP components
|
48
50
|
logger = logging.getLogger("dacp")
|
49
51
|
logger.setLevel(getattr(logging, level.upper()))
|
50
|
-
|
52
|
+
|
51
53
|
# Remove existing handlers to avoid duplicates
|
52
54
|
for handler in logger.handlers[:]:
|
53
55
|
logger.removeHandler(handler)
|
54
|
-
|
56
|
+
|
55
57
|
# Create formatter
|
56
58
|
formatter = logging.Formatter(
|
57
|
-
log_format,
|
58
|
-
datefmt="%Y-%m-%d %H:%M:%S" if include_timestamp else None
|
59
|
+
log_format, datefmt="%Y-%m-%d %H:%M:%S" if include_timestamp else None
|
59
60
|
)
|
60
|
-
|
61
|
+
|
61
62
|
# Console handler
|
62
63
|
console_handler = logging.StreamHandler(sys.stdout)
|
63
64
|
console_handler.setFormatter(formatter)
|
64
65
|
logger.addHandler(console_handler)
|
65
|
-
|
66
|
+
|
66
67
|
# Optional file handler
|
67
68
|
if log_file:
|
68
69
|
file_handler = logging.FileHandler(log_file)
|
69
70
|
file_handler.setFormatter(formatter)
|
70
71
|
logger.addHandler(file_handler)
|
71
|
-
|
72
|
+
|
72
73
|
# Prevent propagation to root logger to avoid duplicate messages
|
73
74
|
logger.propagate = False
|
74
|
-
|
75
|
+
|
75
76
|
logger.info(f"🚀 DACP logging configured: level={level}, style={format_style}")
|
76
77
|
|
77
78
|
|
78
79
|
def set_dacp_log_level(level: str) -> None:
|
79
80
|
"""
|
80
81
|
Set the log level for all DACP components.
|
81
|
-
|
82
|
+
|
82
83
|
Args:
|
83
84
|
level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
84
85
|
"""
|
@@ -102,10 +103,10 @@ def enable_dacp_logging() -> None:
|
|
102
103
|
def get_dacp_logger(name: str) -> logging.Logger:
|
103
104
|
"""
|
104
105
|
Get a logger for a DACP component.
|
105
|
-
|
106
|
+
|
106
107
|
Args:
|
107
108
|
name: Logger name (usually __name__)
|
108
|
-
|
109
|
+
|
109
110
|
Returns:
|
110
111
|
Configured logger
|
111
112
|
"""
|
@@ -125,4 +126,4 @@ def enable_info_logging(log_file: Optional[str] = None) -> None:
|
|
125
126
|
|
126
127
|
def enable_quiet_logging() -> None:
|
127
128
|
"""Enable only error and critical logging."""
|
128
|
-
setup_dacp_logging(level="ERROR", format_style="simple", include_timestamp=False)
|
129
|
+
setup_dacp_logging(level="ERROR", format_style="simple", include_timestamp=False)
|
dacp/main.py
CHANGED
@@ -1,15 +1,9 @@
|
|
1
|
-
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
DACP Main Entry Point
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
+
This module provides examples and testing functionality for DACP.
|
6
|
+
"""
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
# Orchestrator sends a message to the agent and prints the response
|
10
|
-
input_message = {"name": "Alice"}
|
11
|
-
response = orchestrator.call_agent("hello_agent", input_message)
|
12
|
-
print("Orchestrator received:", response)
|
13
|
-
|
14
|
-
if __name__ == "__main__":
|
15
|
-
main()
|
8
|
+
print("DACP - Declarative Agent Communication Protocol")
|
9
|
+
print("For examples, see the examples/ directory")
|
dacp/orchestrator.py
CHANGED
@@ -1,248 +1,284 @@
|
|
1
1
|
"""
|
2
|
-
DACP Orchestrator -
|
2
|
+
DACP Orchestrator - Agent management and message routing.
|
3
|
+
|
4
|
+
This module provides the core orchestrator functionality for managing agents
|
5
|
+
and routing messages between them.
|
3
6
|
"""
|
4
7
|
|
5
8
|
import logging
|
6
9
|
import time
|
7
10
|
from typing import Dict, Any, List, Optional
|
8
|
-
|
9
|
-
from .
|
10
|
-
|
11
|
-
is_tool_request,
|
12
|
-
get_tool_request,
|
13
|
-
wrap_tool_result,
|
14
|
-
is_final_response,
|
15
|
-
get_final_response,
|
16
|
-
)
|
17
|
-
|
18
|
-
# Set up logger for this module
|
11
|
+
|
12
|
+
from .tools import execute_tool
|
13
|
+
|
19
14
|
logger = logging.getLogger("dacp.orchestrator")
|
20
15
|
|
21
16
|
|
22
17
|
class Agent:
|
23
|
-
"""
|
24
|
-
|
18
|
+
"""
|
19
|
+
Base agent class that all DACP agents should inherit from.
|
20
|
+
|
21
|
+
This provides the standard interface for agent communication.
|
22
|
+
"""
|
23
|
+
|
25
24
|
def handle_message(self, message: Dict[str, Any]) -> Dict[str, Any]:
|
26
|
-
"""
|
25
|
+
"""
|
26
|
+
Handle incoming messages.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
message: Message dictionary containing task and parameters
|
30
|
+
|
31
|
+
Returns:
|
32
|
+
Response dictionary with either 'response', 'tool_request', or 'error'
|
33
|
+
"""
|
27
34
|
raise NotImplementedError("Agents must implement handle_message method")
|
28
35
|
|
29
36
|
|
30
37
|
class Orchestrator:
|
31
38
|
"""
|
32
39
|
Central orchestrator for managing agents and routing messages.
|
40
|
+
|
41
|
+
The orchestrator handles agent registration, message routing, tool execution,
|
42
|
+
and conversation history management.
|
33
43
|
"""
|
34
|
-
|
35
|
-
def __init__(self):
|
36
|
-
"""Initialize
|
37
|
-
self.agents: Dict[str,
|
44
|
+
|
45
|
+
def __init__(self, session_id: Optional[str] = None):
|
46
|
+
"""Initialize orchestrator with optional session ID."""
|
47
|
+
self.agents: Dict[str, Agent] = {}
|
48
|
+
self.session_id = session_id or f"session_{int(time.time())}"
|
38
49
|
self.conversation_history: List[Dict[str, Any]] = []
|
39
|
-
|
50
|
+
|
40
51
|
logger.info(f"🎭 Orchestrator initialized with session ID: {self.session_id}")
|
41
|
-
|
42
|
-
def register_agent(self,
|
52
|
+
|
53
|
+
def register_agent(self, name: str, agent: Agent) -> None:
|
43
54
|
"""
|
44
55
|
Register an agent with the orchestrator.
|
45
|
-
|
56
|
+
|
46
57
|
Args:
|
47
|
-
|
48
|
-
agent: Agent instance
|
58
|
+
name: Unique name for the agent
|
59
|
+
agent: Agent instance implementing the Agent interface
|
49
60
|
"""
|
50
|
-
if not
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
61
|
+
if not isinstance(agent, Agent):
|
62
|
+
raise ValueError("Agent must inherit from dacp.Agent base class")
|
63
|
+
|
64
|
+
self.agents[name] = agent
|
65
|
+
logger.info(
|
66
|
+
f"✅ Agent '{name}' registered successfully "
|
67
|
+
f"(type: {type(agent).__name__})"
|
68
|
+
)
|
56
69
|
logger.debug(f"📊 Total registered agents: {len(self.agents)}")
|
57
|
-
|
58
|
-
def unregister_agent(self,
|
70
|
+
|
71
|
+
def unregister_agent(self, name: str) -> bool:
|
59
72
|
"""
|
60
73
|
Unregister an agent from the orchestrator.
|
61
|
-
|
74
|
+
|
62
75
|
Args:
|
63
|
-
|
64
|
-
|
76
|
+
name: Name of the agent to unregister
|
77
|
+
|
65
78
|
Returns:
|
66
|
-
True if agent was
|
79
|
+
True if agent was unregistered, False if not found
|
67
80
|
"""
|
68
|
-
if
|
69
|
-
|
70
|
-
|
71
|
-
logger.
|
72
|
-
logger.debug(f"📊 Remaining registered agents: {len(self.agents)}")
|
81
|
+
if name in self.agents:
|
82
|
+
del self.agents[name]
|
83
|
+
logger.info(f"🗑️ Agent '{name}' unregistered successfully")
|
84
|
+
logger.debug(f"📊 Remaining agents: {len(self.agents)}")
|
73
85
|
return True
|
74
86
|
else:
|
75
|
-
logger.warning(f"⚠️
|
87
|
+
logger.warning(f"⚠️ Agent '{name}' not found for unregistration")
|
76
88
|
return False
|
77
|
-
|
78
|
-
def
|
89
|
+
|
90
|
+
def list_agents(self) -> List[str]:
|
91
|
+
"""Get list of registered agent names."""
|
92
|
+
return list(self.agents.keys())
|
93
|
+
|
94
|
+
def send_message(self, agent_name: str, message: Dict[str, Any]) -> Dict[str, Any]:
|
79
95
|
"""
|
80
96
|
Send a message to a specific agent.
|
81
|
-
|
97
|
+
|
82
98
|
Args:
|
83
|
-
|
84
|
-
message: Message to send
|
85
|
-
|
99
|
+
agent_name: Name of the target agent
|
100
|
+
message: Message dictionary to send
|
101
|
+
|
86
102
|
Returns:
|
87
|
-
Response from the agent
|
103
|
+
Response from the agent after processing
|
88
104
|
"""
|
89
|
-
|
105
|
+
start_time = time.time()
|
106
|
+
|
107
|
+
logger.info(f"📨 Sending message to agent '{agent_name}'")
|
90
108
|
logger.debug(f"📋 Message content: {message}")
|
91
|
-
|
92
|
-
if
|
93
|
-
error_msg = f"Agent '{
|
109
|
+
|
110
|
+
if agent_name not in self.agents:
|
111
|
+
error_msg = f"Agent '{agent_name}' not found"
|
94
112
|
logger.error(f"❌ {error_msg}")
|
95
|
-
logger.debug(f"📊 Available agents: {list(self.agents.keys())}")
|
96
113
|
return {"error": error_msg}
|
97
|
-
|
98
|
-
agent = self.agents[
|
99
|
-
|
114
|
+
|
115
|
+
agent = self.agents[agent_name]
|
116
|
+
|
100
117
|
try:
|
101
|
-
|
102
|
-
|
103
|
-
|
118
|
+
logger.debug(f"🔄 Calling handle_message on agent '{agent_name}'")
|
119
|
+
|
120
|
+
# Call the agent's message handler
|
104
121
|
response = agent.handle_message(message)
|
105
|
-
|
106
|
-
|
107
|
-
logger.info(f"✅ Agent '{
|
122
|
+
|
123
|
+
duration = time.time() - start_time
|
124
|
+
logger.info(f"✅ Agent '{agent_name}' responded in {duration:.3f}s")
|
108
125
|
logger.debug(f"📤 Agent response: {response}")
|
109
|
-
|
110
|
-
# Check if agent requested
|
111
|
-
if
|
112
|
-
logger.info(f"🔧 Agent '{
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
tool_execution_time = time.time() - tool_start_time
|
121
|
-
|
122
|
-
logger.info(f"✅ Tool '{tool_name}' executed successfully in {tool_execution_time:.3f}s")
|
123
|
-
logger.debug(f"🔧 Tool result: {tool_result}")
|
124
|
-
|
125
|
-
wrapped_result = wrap_tool_result(tool_name, tool_result)
|
126
|
-
|
127
|
-
# Log the conversation
|
128
|
-
self._log_conversation(agent_id, message, wrapped_result, tool_used=tool_name)
|
129
|
-
|
130
|
-
return wrapped_result
|
131
|
-
|
132
|
-
except Exception as e:
|
133
|
-
error_msg = f"Tool '{tool_name}' execution failed: {str(e)}"
|
134
|
-
logger.error(f"❌ {error_msg}")
|
135
|
-
error_response = {"error": error_msg}
|
136
|
-
self._log_conversation(agent_id, message, error_response, tool_used=tool_name)
|
137
|
-
return error_response
|
138
|
-
else:
|
139
|
-
error_msg = f"Unknown tool requested: '{tool_name}'"
|
140
|
-
logger.error(f"❌ {error_msg}")
|
141
|
-
logger.debug(f"📊 Available tools: {list(TOOL_REGISTRY.keys())}")
|
142
|
-
error_response = {"error": error_msg}
|
143
|
-
self._log_conversation(agent_id, message, error_response)
|
144
|
-
return error_response
|
145
|
-
|
146
|
-
# Log successful conversation
|
147
|
-
self._log_conversation(agent_id, message, response)
|
126
|
+
|
127
|
+
# Check if agent requested tool execution
|
128
|
+
if isinstance(response, dict) and "tool_request" in response:
|
129
|
+
logger.info(f"🔧 Agent '{agent_name}' requested tool execution")
|
130
|
+
response = self._handle_tool_request(
|
131
|
+
agent_name, response["tool_request"]
|
132
|
+
)
|
133
|
+
|
134
|
+
# Log the conversation
|
135
|
+
self._log_conversation(agent_name, message, response, duration)
|
136
|
+
|
148
137
|
return response
|
149
|
-
|
138
|
+
|
150
139
|
except Exception as e:
|
151
|
-
|
140
|
+
duration = time.time() - start_time
|
141
|
+
error_msg = f"Error in agent '{agent_name}': {type(e).__name__}: {e}"
|
152
142
|
logger.error(f"❌ {error_msg}")
|
153
|
-
logger.debug(
|
143
|
+
logger.debug("💥 Exception details", exc_info=True)
|
144
|
+
|
154
145
|
error_response = {"error": error_msg}
|
155
|
-
self._log_conversation(
|
146
|
+
self._log_conversation(agent_name, message, error_response, duration)
|
147
|
+
|
156
148
|
return error_response
|
157
|
-
|
158
|
-
def broadcast_message(self, message: Dict[str, Any]
|
149
|
+
|
150
|
+
def broadcast_message(self, message: Dict[str, Any]) -> Dict[str, Any]:
|
159
151
|
"""
|
160
|
-
Send a message to all registered agents
|
161
|
-
|
152
|
+
Send a message to all registered agents.
|
153
|
+
|
162
154
|
Args:
|
163
|
-
message: Message to broadcast
|
164
|
-
|
165
|
-
|
155
|
+
message: Message dictionary to broadcast
|
156
|
+
|
166
157
|
Returns:
|
167
|
-
|
158
|
+
Dictionary mapping agent names to their responses
|
168
159
|
"""
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
logger.info(f"📡 Broadcasting message to {len(target_agents)} agents")
|
173
|
-
logger.debug(f"🎯 Target agents: {target_agents}")
|
174
|
-
if exclude_agents:
|
175
|
-
logger.debug(f"🚫 Excluded agents: {exclude_agents}")
|
176
|
-
|
160
|
+
logger.info(f"📢 Broadcasting message to {len(self.agents)} agents")
|
161
|
+
logger.debug(f"📋 Broadcast message: {message}")
|
162
|
+
|
177
163
|
responses = {}
|
178
164
|
start_time = time.time()
|
179
|
-
|
180
|
-
for
|
181
|
-
logger.debug(f"📨 Broadcasting to agent '{
|
182
|
-
responses[
|
183
|
-
|
184
|
-
|
185
|
-
logger.info(
|
186
|
-
|
165
|
+
|
166
|
+
for agent_name in self.agents:
|
167
|
+
logger.debug(f"📨 Broadcasting to agent '{agent_name}'")
|
168
|
+
responses[agent_name] = self.send_message(agent_name, message)
|
169
|
+
|
170
|
+
duration = time.time() - start_time
|
171
|
+
logger.info(
|
172
|
+
f"✅ Broadcast completed in {duration:.3f}s "
|
173
|
+
f"({len(responses)} responses)"
|
174
|
+
)
|
175
|
+
|
187
176
|
return responses
|
188
|
-
|
189
|
-
def
|
177
|
+
|
178
|
+
def _handle_tool_request(
|
179
|
+
self, agent_name: str, tool_request: Dict[str, Any]
|
180
|
+
) -> Dict[str, Any]:
|
190
181
|
"""
|
191
|
-
|
192
|
-
|
182
|
+
Handle tool execution request from an agent.
|
183
|
+
|
193
184
|
Args:
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
List of conversation entries
|
198
|
-
"""
|
199
|
-
if agent_id is None:
|
200
|
-
logger.debug(f"📚 Retrieving full conversation history ({len(self.conversation_history)} entries)")
|
201
|
-
return self.conversation_history.copy()
|
202
|
-
else:
|
203
|
-
filtered_history = [
|
204
|
-
entry for entry in self.conversation_history
|
205
|
-
if entry.get("agent_id") == agent_id
|
206
|
-
]
|
207
|
-
logger.debug(f"📚 Retrieving conversation history for '{agent_id}' ({len(filtered_history)} entries)")
|
208
|
-
return filtered_history
|
209
|
-
|
210
|
-
def clear_history(self) -> None:
|
211
|
-
"""Clear the conversation history."""
|
212
|
-
old_count = len(self.conversation_history)
|
213
|
-
self.conversation_history.clear()
|
214
|
-
logger.info(f"🗑️ Conversation history cleared ({old_count} entries removed)")
|
215
|
-
|
216
|
-
def get_session_info(self) -> Dict[str, Any]:
|
217
|
-
"""
|
218
|
-
Get current session information.
|
219
|
-
|
185
|
+
agent_name: Name of the requesting agent
|
186
|
+
tool_request: Tool request dictionary with 'name' and 'args'
|
187
|
+
|
220
188
|
Returns:
|
221
|
-
|
189
|
+
Tool execution result
|
222
190
|
"""
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
"
|
228
|
-
|
229
|
-
logger.
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
191
|
+
tool_name = tool_request.get("name")
|
192
|
+
tool_args = tool_request.get("args", {})
|
193
|
+
|
194
|
+
if not tool_name:
|
195
|
+
return {"error": "Tool name is required"}
|
196
|
+
|
197
|
+
logger.info(f"🛠️ Executing tool: '{tool_name}' with args: {tool_args}")
|
198
|
+
|
199
|
+
start_time = time.time()
|
200
|
+
|
201
|
+
try:
|
202
|
+
result = execute_tool(tool_name, tool_args)
|
203
|
+
duration = time.time() - start_time
|
204
|
+
|
205
|
+
logger.info(
|
206
|
+
f"✅ Tool '{tool_name}' executed successfully in {duration:.3f}s"
|
207
|
+
)
|
208
|
+
logger.debug(f"🔧 Tool result: {result}")
|
209
|
+
|
210
|
+
return {"tool_result": {"name": tool_name, "result": result}}
|
211
|
+
|
212
|
+
except Exception as e:
|
213
|
+
duration = time.time() - start_time
|
214
|
+
error_msg = f"Tool '{tool_name}' failed: {type(e).__name__}: {e}"
|
215
|
+
logger.error(f"❌ {error_msg}")
|
216
|
+
|
217
|
+
return {"error": error_msg}
|
218
|
+
|
219
|
+
def _log_conversation(
|
220
|
+
self,
|
221
|
+
agent_name: str,
|
222
|
+
message: Dict[str, Any],
|
223
|
+
response: Dict[str, Any],
|
224
|
+
duration: float,
|
225
|
+
) -> None:
|
226
|
+
"""Log conversation entry to history."""
|
227
|
+
logger.debug("💾 Logging conversation entry")
|
228
|
+
|
234
229
|
entry = {
|
235
230
|
"timestamp": time.time(),
|
236
|
-
"
|
231
|
+
"session_id": self.session_id,
|
232
|
+
"agent_name": agent_name,
|
237
233
|
"message": message,
|
238
234
|
"response": response,
|
239
|
-
"
|
235
|
+
"duration": duration,
|
240
236
|
}
|
241
|
-
|
242
|
-
if tool_used:
|
243
|
-
entry["tool_used"] = tool_used
|
244
|
-
logger.debug(f"💾 Logging conversation with tool usage: {tool_used}")
|
245
|
-
else:
|
246
|
-
logger.debug(f"💾 Logging conversation entry")
|
247
|
-
|
237
|
+
|
248
238
|
self.conversation_history.append(entry)
|
239
|
+
|
240
|
+
# Keep history manageable (last 1000 entries)
|
241
|
+
if len(self.conversation_history) > 1000:
|
242
|
+
self.conversation_history = self.conversation_history[-1000:]
|
243
|
+
logger.debug("🗂️ Conversation history trimmed to 1000 entries")
|
244
|
+
|
245
|
+
def get_conversation_history(
|
246
|
+
self, limit: Optional[int] = None
|
247
|
+
) -> List[Dict[str, Any]]:
|
248
|
+
"""
|
249
|
+
Get conversation history.
|
250
|
+
|
251
|
+
Args:
|
252
|
+
limit: Maximum number of entries to return (None for all)
|
253
|
+
|
254
|
+
Returns:
|
255
|
+
List of conversation entries
|
256
|
+
"""
|
257
|
+
if limit is None:
|
258
|
+
return self.conversation_history.copy()
|
259
|
+
else:
|
260
|
+
return self.conversation_history[-limit:].copy()
|
261
|
+
|
262
|
+
def clear_conversation_history(self) -> None:
|
263
|
+
"""Clear conversation history."""
|
264
|
+
self.conversation_history.clear()
|
265
|
+
logger.info("🗑️ Conversation history cleared")
|
266
|
+
|
267
|
+
def get_session_metadata(self) -> Dict[str, Any]:
|
268
|
+
"""Get session metadata and statistics."""
|
269
|
+
return {
|
270
|
+
"session_id": self.session_id,
|
271
|
+
"registered_agents": len(self.agents),
|
272
|
+
"agent_names": list(self.agents.keys()),
|
273
|
+
"conversation_entries": len(self.conversation_history),
|
274
|
+
"start_time": (
|
275
|
+
self.conversation_history[0]["timestamp"]
|
276
|
+
if self.conversation_history
|
277
|
+
else None
|
278
|
+
),
|
279
|
+
"last_activity": (
|
280
|
+
self.conversation_history[-1]["timestamp"]
|
281
|
+
if self.conversation_history
|
282
|
+
else None
|
283
|
+
),
|
284
|
+
}
|