aiecs 1.3.8__py3-none-any.whl → 1.4.0__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.
Potentially problematic release.
This version of aiecs might be problematic. Click here for more details.
- aiecs/__init__.py +1 -1
- aiecs/domain/__init__.py +120 -0
- aiecs/domain/agent/__init__.py +184 -0
- aiecs/domain/agent/base_agent.py +691 -0
- aiecs/domain/agent/exceptions.py +99 -0
- aiecs/domain/agent/hybrid_agent.py +495 -0
- aiecs/domain/agent/integration/__init__.py +23 -0
- aiecs/domain/agent/integration/context_compressor.py +219 -0
- aiecs/domain/agent/integration/context_engine_adapter.py +258 -0
- aiecs/domain/agent/integration/retry_policy.py +228 -0
- aiecs/domain/agent/integration/role_config.py +217 -0
- aiecs/domain/agent/lifecycle.py +298 -0
- aiecs/domain/agent/llm_agent.py +309 -0
- aiecs/domain/agent/memory/__init__.py +13 -0
- aiecs/domain/agent/memory/conversation.py +216 -0
- aiecs/domain/agent/migration/__init__.py +15 -0
- aiecs/domain/agent/migration/conversion.py +171 -0
- aiecs/domain/agent/migration/legacy_wrapper.py +97 -0
- aiecs/domain/agent/models.py +263 -0
- aiecs/domain/agent/observability.py +443 -0
- aiecs/domain/agent/persistence.py +287 -0
- aiecs/domain/agent/prompts/__init__.py +25 -0
- aiecs/domain/agent/prompts/builder.py +164 -0
- aiecs/domain/agent/prompts/formatters.py +192 -0
- aiecs/domain/agent/prompts/template.py +264 -0
- aiecs/domain/agent/registry.py +261 -0
- aiecs/domain/agent/tool_agent.py +267 -0
- aiecs/domain/agent/tools/__init__.py +13 -0
- aiecs/domain/agent/tools/schema_generator.py +222 -0
- aiecs/main.py +2 -2
- {aiecs-1.3.8.dist-info → aiecs-1.4.0.dist-info}/METADATA +1 -1
- {aiecs-1.3.8.dist-info → aiecs-1.4.0.dist-info}/RECORD +36 -9
- {aiecs-1.3.8.dist-info → aiecs-1.4.0.dist-info}/WHEEL +0 -0
- {aiecs-1.3.8.dist-info → aiecs-1.4.0.dist-info}/entry_points.txt +0 -0
- {aiecs-1.3.8.dist-info → aiecs-1.4.0.dist-info}/licenses/LICENSE +0 -0
- {aiecs-1.3.8.dist-info → aiecs-1.4.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Prompt Templates
|
|
3
|
+
|
|
4
|
+
Native template system with variable substitution.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
from typing import Dict, Any, List, Optional
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
from aiecs.llm import LLMMessage
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TemplateMissingVariableError(Exception):
|
|
15
|
+
"""Raised when required template variable is missing."""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class PromptTemplate:
|
|
20
|
+
"""
|
|
21
|
+
String-based prompt template with {variable} substitution.
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
template = PromptTemplate(
|
|
25
|
+
"Hello {name}, you are a {role}.",
|
|
26
|
+
required_variables=["name", "role"]
|
|
27
|
+
)
|
|
28
|
+
result = template.format(name="Alice", role="developer")
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
template: str,
|
|
34
|
+
required_variables: Optional[List[str]] = None,
|
|
35
|
+
defaults: Optional[Dict[str, str]] = None,
|
|
36
|
+
):
|
|
37
|
+
"""
|
|
38
|
+
Initialize prompt template.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
template: Template string with {variable} placeholders
|
|
42
|
+
required_variables: List of required variable names
|
|
43
|
+
defaults: Default values for optional variables
|
|
44
|
+
"""
|
|
45
|
+
self.template = template
|
|
46
|
+
self.required_variables = required_variables or []
|
|
47
|
+
self.defaults = defaults or {}
|
|
48
|
+
|
|
49
|
+
# Extract all variables from template
|
|
50
|
+
self._extract_variables()
|
|
51
|
+
|
|
52
|
+
def _extract_variables(self) -> None:
|
|
53
|
+
"""Extract variable names from template."""
|
|
54
|
+
# Find all {variable_name} patterns
|
|
55
|
+
pattern = r'\{(\w+)\}'
|
|
56
|
+
self.variables = set(re.findall(pattern, self.template))
|
|
57
|
+
|
|
58
|
+
def format(self, **kwargs) -> str:
|
|
59
|
+
"""
|
|
60
|
+
Format template with provided variables.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
**kwargs: Variable values
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Formatted string
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
TemplateMissingVariableError: If required variable missing
|
|
70
|
+
"""
|
|
71
|
+
# Check required variables
|
|
72
|
+
for var in self.required_variables:
|
|
73
|
+
if var not in kwargs and var not in self.defaults:
|
|
74
|
+
raise TemplateMissingVariableError(
|
|
75
|
+
f"Required variable '{var}' not provided"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Merge with defaults
|
|
79
|
+
values = {**self.defaults, **kwargs}
|
|
80
|
+
|
|
81
|
+
# Format template
|
|
82
|
+
try:
|
|
83
|
+
return self.template.format(**values)
|
|
84
|
+
except KeyError as e:
|
|
85
|
+
raise TemplateMissingVariableError(
|
|
86
|
+
f"Variable {e} not provided and has no default"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
def partial(self, **kwargs) -> "PromptTemplate":
|
|
90
|
+
"""
|
|
91
|
+
Create a partial template with some variables pre-filled.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
**kwargs: Variable values to pre-fill
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
New PromptTemplate with updated defaults
|
|
98
|
+
"""
|
|
99
|
+
new_defaults = {**self.defaults, **kwargs}
|
|
100
|
+
return PromptTemplate(
|
|
101
|
+
template=self.template,
|
|
102
|
+
required_variables=self.required_variables,
|
|
103
|
+
defaults=new_defaults,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def __repr__(self) -> str:
|
|
107
|
+
return f"PromptTemplate(variables={self.variables})"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@dataclass
|
|
111
|
+
class MessageTemplate:
|
|
112
|
+
"""Template for a single message."""
|
|
113
|
+
role: str
|
|
114
|
+
content: str
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class ChatPromptTemplate:
|
|
118
|
+
"""
|
|
119
|
+
Multi-message chat template.
|
|
120
|
+
|
|
121
|
+
Example:
|
|
122
|
+
template = ChatPromptTemplate([
|
|
123
|
+
MessageTemplate("system", "You are a {role}."),
|
|
124
|
+
MessageTemplate("user", "{task}"),
|
|
125
|
+
])
|
|
126
|
+
messages = template.format_messages(role="assistant", task="Help me")
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
def __init__(
|
|
130
|
+
self,
|
|
131
|
+
messages: List[MessageTemplate],
|
|
132
|
+
required_variables: Optional[List[str]] = None,
|
|
133
|
+
defaults: Optional[Dict[str, str]] = None,
|
|
134
|
+
):
|
|
135
|
+
"""
|
|
136
|
+
Initialize chat template.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
messages: List of message templates
|
|
140
|
+
required_variables: List of required variable names
|
|
141
|
+
defaults: Default values for optional variables
|
|
142
|
+
"""
|
|
143
|
+
self.messages = messages
|
|
144
|
+
self.required_variables = required_variables or []
|
|
145
|
+
self.defaults = defaults or {}
|
|
146
|
+
|
|
147
|
+
# Extract all variables
|
|
148
|
+
self._extract_variables()
|
|
149
|
+
|
|
150
|
+
def _extract_variables(self) -> None:
|
|
151
|
+
"""Extract variables from all message templates."""
|
|
152
|
+
self.variables = set()
|
|
153
|
+
pattern = r'\{(\w+)\}'
|
|
154
|
+
|
|
155
|
+
for msg in self.messages:
|
|
156
|
+
vars_in_msg = set(re.findall(pattern, msg.content))
|
|
157
|
+
self.variables.update(vars_in_msg)
|
|
158
|
+
|
|
159
|
+
def format_messages(self, **kwargs) -> List[LLMMessage]:
|
|
160
|
+
"""
|
|
161
|
+
Format all messages with provided variables.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
**kwargs: Variable values
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
List of LLMMessage instances
|
|
168
|
+
|
|
169
|
+
Raises:
|
|
170
|
+
TemplateMissingVariableError: If required variable missing
|
|
171
|
+
"""
|
|
172
|
+
# Check required variables
|
|
173
|
+
for var in self.required_variables:
|
|
174
|
+
if var not in kwargs and var not in self.defaults:
|
|
175
|
+
raise TemplateMissingVariableError(
|
|
176
|
+
f"Required variable '{var}' not provided"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Merge with defaults
|
|
180
|
+
values = {**self.defaults, **kwargs}
|
|
181
|
+
|
|
182
|
+
# Format each message
|
|
183
|
+
formatted_messages = []
|
|
184
|
+
for msg_template in self.messages:
|
|
185
|
+
try:
|
|
186
|
+
content = msg_template.content.format(**values)
|
|
187
|
+
formatted_messages.append(
|
|
188
|
+
LLMMessage(role=msg_template.role, content=content)
|
|
189
|
+
)
|
|
190
|
+
except KeyError as e:
|
|
191
|
+
raise TemplateMissingVariableError(
|
|
192
|
+
f"Variable {e} not provided and has no default"
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
return formatted_messages
|
|
196
|
+
|
|
197
|
+
def partial(self, **kwargs) -> "ChatPromptTemplate":
|
|
198
|
+
"""
|
|
199
|
+
Create a partial template with some variables pre-filled.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
**kwargs: Variable values to pre-fill
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
New ChatPromptTemplate with updated defaults
|
|
206
|
+
"""
|
|
207
|
+
new_defaults = {**self.defaults, **kwargs}
|
|
208
|
+
return ChatPromptTemplate(
|
|
209
|
+
messages=self.messages,
|
|
210
|
+
required_variables=self.required_variables,
|
|
211
|
+
defaults=new_defaults,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
def add_message(self, role: str, content: str) -> "ChatPromptTemplate":
|
|
215
|
+
"""
|
|
216
|
+
Add a message to the template.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
role: Message role
|
|
220
|
+
content: Message content template
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
New ChatPromptTemplate with added message
|
|
224
|
+
"""
|
|
225
|
+
new_messages = self.messages + [MessageTemplate(role, content)]
|
|
226
|
+
return ChatPromptTemplate(
|
|
227
|
+
messages=new_messages,
|
|
228
|
+
required_variables=self.required_variables,
|
|
229
|
+
defaults=self.defaults,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
def __repr__(self) -> str:
|
|
233
|
+
return f"ChatPromptTemplate(messages={len(self.messages)}, variables={self.variables})"
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def create_system_prompt(content: str) -> ChatPromptTemplate:
|
|
237
|
+
"""
|
|
238
|
+
Helper to create a chat template with system message.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
content: System message content
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
ChatPromptTemplate with system message
|
|
245
|
+
"""
|
|
246
|
+
return ChatPromptTemplate([MessageTemplate("system", content)])
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def create_basic_chat(system: str, user: str) -> ChatPromptTemplate:
|
|
250
|
+
"""
|
|
251
|
+
Helper to create a basic system + user chat template.
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
system: System message content
|
|
255
|
+
user: User message content
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
ChatPromptTemplate with system and user messages
|
|
259
|
+
"""
|
|
260
|
+
return ChatPromptTemplate([
|
|
261
|
+
MessageTemplate("system", system),
|
|
262
|
+
MessageTemplate("user", user),
|
|
263
|
+
])
|
|
264
|
+
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Registry
|
|
3
|
+
|
|
4
|
+
Central registry for tracking and managing active agents.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Dict, List, Optional, Set
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
|
|
11
|
+
from .base_agent import BaseAIAgent
|
|
12
|
+
from .models import AgentState, AgentType
|
|
13
|
+
from .exceptions import AgentNotFoundError, AgentAlreadyRegisteredError
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AgentRegistry:
|
|
19
|
+
"""
|
|
20
|
+
Central registry for tracking and managing active agents.
|
|
21
|
+
|
|
22
|
+
Thread-safe registry for agent lifecycle management.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self):
|
|
26
|
+
"""Initialize agent registry."""
|
|
27
|
+
self._agents: Dict[str, BaseAIAgent] = {}
|
|
28
|
+
self._agents_by_type: Dict[AgentType, Set[str]] = {}
|
|
29
|
+
self._agents_by_state: Dict[AgentState, Set[str]] = {}
|
|
30
|
+
|
|
31
|
+
logger.info("AgentRegistry initialized")
|
|
32
|
+
|
|
33
|
+
def register(self, agent: BaseAIAgent) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Register an agent.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
agent: Agent to register
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
AgentAlreadyRegisteredError: If agent already registered
|
|
42
|
+
"""
|
|
43
|
+
if agent.agent_id in self._agents:
|
|
44
|
+
raise AgentAlreadyRegisteredError(agent.agent_id)
|
|
45
|
+
|
|
46
|
+
# Register agent
|
|
47
|
+
self._agents[agent.agent_id] = agent
|
|
48
|
+
|
|
49
|
+
# Index by type
|
|
50
|
+
if agent.agent_type not in self._agents_by_type:
|
|
51
|
+
self._agents_by_type[agent.agent_type] = set()
|
|
52
|
+
self._agents_by_type[agent.agent_type].add(agent.agent_id)
|
|
53
|
+
|
|
54
|
+
# Index by state
|
|
55
|
+
if agent.state not in self._agents_by_state:
|
|
56
|
+
self._agents_by_state[agent.state] = set()
|
|
57
|
+
self._agents_by_state[agent.state].add(agent.agent_id)
|
|
58
|
+
|
|
59
|
+
logger.info(f"Agent registered: {agent.agent_id} ({agent.agent_type.value})")
|
|
60
|
+
|
|
61
|
+
def unregister(self, agent_id: str) -> None:
|
|
62
|
+
"""
|
|
63
|
+
Unregister an agent.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
agent_id: Agent identifier
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
AgentNotFoundError: If agent not found
|
|
70
|
+
"""
|
|
71
|
+
agent = self.get(agent_id)
|
|
72
|
+
|
|
73
|
+
# Remove from indexes
|
|
74
|
+
if agent.agent_type in self._agents_by_type:
|
|
75
|
+
self._agents_by_type[agent.agent_type].discard(agent_id)
|
|
76
|
+
|
|
77
|
+
if agent.state in self._agents_by_state:
|
|
78
|
+
self._agents_by_state[agent.state].discard(agent_id)
|
|
79
|
+
|
|
80
|
+
# Remove from main registry
|
|
81
|
+
del self._agents[agent_id]
|
|
82
|
+
|
|
83
|
+
logger.info(f"Agent unregistered: {agent_id}")
|
|
84
|
+
|
|
85
|
+
def get(self, agent_id: str) -> BaseAIAgent:
|
|
86
|
+
"""
|
|
87
|
+
Get agent by ID.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
agent_id: Agent identifier
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Agent instance
|
|
94
|
+
|
|
95
|
+
Raises:
|
|
96
|
+
AgentNotFoundError: If agent not found
|
|
97
|
+
"""
|
|
98
|
+
if agent_id not in self._agents:
|
|
99
|
+
raise AgentNotFoundError(agent_id)
|
|
100
|
+
|
|
101
|
+
return self._agents[agent_id]
|
|
102
|
+
|
|
103
|
+
def get_optional(self, agent_id: str) -> Optional[BaseAIAgent]:
|
|
104
|
+
"""
|
|
105
|
+
Get agent by ID, returning None if not found.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
agent_id: Agent identifier
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
Agent instance or None
|
|
112
|
+
"""
|
|
113
|
+
return self._agents.get(agent_id)
|
|
114
|
+
|
|
115
|
+
def exists(self, agent_id: str) -> bool:
|
|
116
|
+
"""
|
|
117
|
+
Check if agent exists.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
agent_id: Agent identifier
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
True if agent exists
|
|
124
|
+
"""
|
|
125
|
+
return agent_id in self._agents
|
|
126
|
+
|
|
127
|
+
def list_all(self) -> List[BaseAIAgent]:
|
|
128
|
+
"""
|
|
129
|
+
List all registered agents.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
List of all agents
|
|
133
|
+
"""
|
|
134
|
+
return list(self._agents.values())
|
|
135
|
+
|
|
136
|
+
def list_by_type(self, agent_type: AgentType) -> List[BaseAIAgent]:
|
|
137
|
+
"""
|
|
138
|
+
List agents by type.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
agent_type: Agent type
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
List of agents of specified type
|
|
145
|
+
"""
|
|
146
|
+
agent_ids = self._agents_by_type.get(agent_type, set())
|
|
147
|
+
return [self._agents[aid] for aid in agent_ids if aid in self._agents]
|
|
148
|
+
|
|
149
|
+
def list_by_state(self, state: AgentState) -> List[BaseAIAgent]:
|
|
150
|
+
"""
|
|
151
|
+
List agents by state.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
state: Agent state
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
List of agents in specified state
|
|
158
|
+
"""
|
|
159
|
+
agent_ids = self._agents_by_state.get(state, set())
|
|
160
|
+
return [self._agents[aid] for aid in agent_ids if aid in self._agents]
|
|
161
|
+
|
|
162
|
+
def update_state_index(self, agent_id: str, old_state: AgentState, new_state: AgentState) -> None:
|
|
163
|
+
"""
|
|
164
|
+
Update state index when agent state changes.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
agent_id: Agent identifier
|
|
168
|
+
old_state: Previous state
|
|
169
|
+
new_state: New state
|
|
170
|
+
"""
|
|
171
|
+
# Remove from old state index
|
|
172
|
+
if old_state in self._agents_by_state:
|
|
173
|
+
self._agents_by_state[old_state].discard(agent_id)
|
|
174
|
+
|
|
175
|
+
# Add to new state index
|
|
176
|
+
if new_state not in self._agents_by_state:
|
|
177
|
+
self._agents_by_state[new_state] = set()
|
|
178
|
+
self._agents_by_state[new_state].add(agent_id)
|
|
179
|
+
|
|
180
|
+
def count(self) -> int:
|
|
181
|
+
"""
|
|
182
|
+
Get total number of registered agents.
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
Number of agents
|
|
186
|
+
"""
|
|
187
|
+
return len(self._agents)
|
|
188
|
+
|
|
189
|
+
def count_by_type(self, agent_type: AgentType) -> int:
|
|
190
|
+
"""
|
|
191
|
+
Get count of agents by type.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
agent_type: Agent type
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Number of agents of specified type
|
|
198
|
+
"""
|
|
199
|
+
return len(self._agents_by_type.get(agent_type, set()))
|
|
200
|
+
|
|
201
|
+
def count_by_state(self, state: AgentState) -> int:
|
|
202
|
+
"""
|
|
203
|
+
Get count of agents by state.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
state: Agent state
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
Number of agents in specified state
|
|
210
|
+
"""
|
|
211
|
+
return len(self._agents_by_state.get(state, set()))
|
|
212
|
+
|
|
213
|
+
def get_stats(self) -> Dict:
|
|
214
|
+
"""
|
|
215
|
+
Get registry statistics.
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
Dictionary with stats
|
|
219
|
+
"""
|
|
220
|
+
return {
|
|
221
|
+
"total_agents": self.count(),
|
|
222
|
+
"by_type": {
|
|
223
|
+
agent_type.value: len(agent_ids)
|
|
224
|
+
for agent_type, agent_ids in self._agents_by_type.items()
|
|
225
|
+
},
|
|
226
|
+
"by_state": {
|
|
227
|
+
state.value: len(agent_ids)
|
|
228
|
+
for state, agent_ids in self._agents_by_state.items()
|
|
229
|
+
},
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
def clear(self) -> None:
|
|
233
|
+
"""Clear all agents from registry."""
|
|
234
|
+
self._agents.clear()
|
|
235
|
+
self._agents_by_type.clear()
|
|
236
|
+
self._agents_by_state.clear()
|
|
237
|
+
logger.info("AgentRegistry cleared")
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
# Global registry instance
|
|
241
|
+
_global_registry: Optional[AgentRegistry] = None
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def get_global_registry() -> AgentRegistry:
|
|
245
|
+
"""
|
|
246
|
+
Get or create global agent registry.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Global AgentRegistry instance
|
|
250
|
+
"""
|
|
251
|
+
global _global_registry
|
|
252
|
+
if _global_registry is None:
|
|
253
|
+
_global_registry = AgentRegistry()
|
|
254
|
+
return _global_registry
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def reset_global_registry() -> None:
|
|
258
|
+
"""Reset global registry (primarily for testing)."""
|
|
259
|
+
global _global_registry
|
|
260
|
+
_global_registry = None
|
|
261
|
+
|