acgp 0.1.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.
- acgp/__init__.py +75 -0
- acgp/adapters/__init__.py +13 -0
- acgp/adapters/crewai.py +400 -0
- acgp/adapters/generic.py +406 -0
- acgp/client.py +825 -0
- acgp/config.py +132 -0
- acgp/models/__init__.py +22 -0
- acgp/models/data_models.py +536 -0
- acgp/py.typed +0 -0
- acgp/transport/__init__.py +24 -0
- acgp/transport/async_queue.py +247 -0
- acgp/transport/batch_sender.py +210 -0
- acgp/transport/retry.py +266 -0
- acgp/transport/sse_client.py +292 -0
- acgp/utils/__init__.py +16 -0
- acgp/utils/observer_interface.py +263 -0
- acgp/wrapper/__init__.py +18 -0
- acgp/wrapper/agent_protocol.py +365 -0
- acgp/wrapper/agent_wrapper.py +531 -0
- acgp/wrapper/decorator.py +354 -0
- acgp-0.1.0.dist-info/METADATA +597 -0
- acgp-0.1.0.dist-info/RECORD +24 -0
- acgp-0.1.0.dist-info/WHEEL +4 -0
- acgp-0.1.0.dist-info/licenses/LICENSE +21 -0
acgp/__init__.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ACGP SDK - Agentic Cognitive Governance Protocol
|
|
3
|
+
Lightweight Python SDK for AI agent oversight integration.
|
|
4
|
+
|
|
5
|
+
Basic Usage (Real-time Feedback - Recommended):
|
|
6
|
+
|
|
7
|
+
from acgp import ACGPClient
|
|
8
|
+
|
|
9
|
+
def handle_feedback(trace_id: str, feedback_data: dict):
|
|
10
|
+
print(f"Feedback for {trace_id}: {feedback_data}")
|
|
11
|
+
|
|
12
|
+
client = ACGPClient(
|
|
13
|
+
api_key="sk_...",
|
|
14
|
+
on_feedback=handle_feedback # Real-time SSE streaming
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
with client.trace(agent_type="planner", goal="Analyze query") as trace:
|
|
18
|
+
result = my_agent.run(query)
|
|
19
|
+
trace.set_output(result)
|
|
20
|
+
# Feedback callback fires automatically!
|
|
21
|
+
|
|
22
|
+
client.wait_for_feedback(timeout=30) # Optional: wait before shutdown
|
|
23
|
+
client.close()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
Alternative Usage (Manual Polling):
|
|
27
|
+
|
|
28
|
+
from acgp import ACGPClient, acgp_trace
|
|
29
|
+
|
|
30
|
+
client = ACGPClient(api_key="sk_...")
|
|
31
|
+
|
|
32
|
+
# Option 1: Decorator
|
|
33
|
+
@acgp_trace(client, agent_type="planner")
|
|
34
|
+
def my_agent(query):
|
|
35
|
+
return process(query)
|
|
36
|
+
|
|
37
|
+
# Option 2: Context manager
|
|
38
|
+
with client.trace(agent_type="executor", goal="Process query") as trace:
|
|
39
|
+
result = my_agent.run(query)
|
|
40
|
+
trace.set_output(result)
|
|
41
|
+
|
|
42
|
+
# Option 3: Manual capture
|
|
43
|
+
trace_id = client.capture_trace(
|
|
44
|
+
agent_type="planner",
|
|
45
|
+
goal="Analyze request",
|
|
46
|
+
final_output="Result..."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Flush and poll for results
|
|
50
|
+
client.flush()
|
|
51
|
+
score = client.get_score(trace_id)
|
|
52
|
+
feedback = client.get_feedback(trace_id)
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
__version__ = "0.1.0"
|
|
56
|
+
|
|
57
|
+
from .client import ACGPClient, acgp_trace, TraceContext, FeedbackCallback
|
|
58
|
+
from .config import ACGPConfig, load_config
|
|
59
|
+
from .transport import BatchResult, QueueConfig, BatchConfig, RetryConfig, SSEConfig
|
|
60
|
+
|
|
61
|
+
__all__ = [
|
|
62
|
+
"__version__",
|
|
63
|
+
"ACGPClient",
|
|
64
|
+
"acgp_trace",
|
|
65
|
+
"TraceContext",
|
|
66
|
+
"FeedbackCallback",
|
|
67
|
+
"ACGPConfig",
|
|
68
|
+
"load_config",
|
|
69
|
+
# Transport (for advanced users)
|
|
70
|
+
"BatchResult",
|
|
71
|
+
"QueueConfig",
|
|
72
|
+
"BatchConfig",
|
|
73
|
+
"RetryConfig",
|
|
74
|
+
"SSEConfig",
|
|
75
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CGP SDK Adapters
|
|
3
|
+
Framework-specific adapters for agent integration.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .generic import GenericAdapter
|
|
7
|
+
|
|
8
|
+
# CrewAI adapter is optional - only import if crewai is installed
|
|
9
|
+
try:
|
|
10
|
+
from .crewai import CrewAIAdapter
|
|
11
|
+
__all__ = ["GenericAdapter", "CrewAIAdapter"]
|
|
12
|
+
except ImportError:
|
|
13
|
+
__all__ = ["GenericAdapter"]
|
acgp/adapters/crewai.py
ADDED
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CrewAI Adapter - Framework-Specific Adapter for CrewAI Agents
|
|
3
|
+
|
|
4
|
+
This adapter enables Steward Agent to monitor CrewAI agents transparently.
|
|
5
|
+
It handles CrewAI-specific output formats, agent structures, and feedback injection.
|
|
6
|
+
|
|
7
|
+
Supports:
|
|
8
|
+
- CrewAI Agent objects
|
|
9
|
+
- CrewAI Crew objects
|
|
10
|
+
- CrewAI Task objects
|
|
11
|
+
- CrewOutput parsing
|
|
12
|
+
- Agent role/goal/backstory extraction
|
|
13
|
+
|
|
14
|
+
Usage Example:
|
|
15
|
+
```python
|
|
16
|
+
from crewai import Agent
|
|
17
|
+
from src.adapters import CrewAIAdapter
|
|
18
|
+
from src.wrapper import StewardAgentWrapper
|
|
19
|
+
from src.core import StewardAgent
|
|
20
|
+
|
|
21
|
+
# Create CrewAI agent
|
|
22
|
+
agent = Agent(
|
|
23
|
+
role="Researcher",
|
|
24
|
+
goal="Find latest AI developments",
|
|
25
|
+
backstory="Expert AI researcher"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# Wrap with Steward Agent monitoring
|
|
29
|
+
adapter = CrewAIAdapter()
|
|
30
|
+
steward = StewardAgent()
|
|
31
|
+
wrapped = StewardAgentWrapper(agent, adapter, steward)
|
|
32
|
+
|
|
33
|
+
# Use normally - monitored automatically
|
|
34
|
+
result = wrapped.execute("Research AI safety")
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Framework Dependency:
|
|
38
|
+
This adapter imports CrewAI but handles ImportError gracefully.
|
|
39
|
+
If CrewAI is not installed, adapter will report it doesn't support agents.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
import logging
|
|
43
|
+
from typing import Any, Dict, Optional, Union
|
|
44
|
+
|
|
45
|
+
# Try to import CrewAI
|
|
46
|
+
try:
|
|
47
|
+
from crewai import Agent, Task, Crew
|
|
48
|
+
from crewai.agent import Agent as CrewAIAgent
|
|
49
|
+
CREWAI_AVAILABLE = True
|
|
50
|
+
except ImportError:
|
|
51
|
+
CREWAI_AVAILABLE = False
|
|
52
|
+
# Placeholders for type hints
|
|
53
|
+
class Agent: pass
|
|
54
|
+
class Task: pass
|
|
55
|
+
class Crew: pass
|
|
56
|
+
class CrewAIAgent: pass
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
from ..wrapper.agent_protocol import (
|
|
60
|
+
AgentAdapter,
|
|
61
|
+
AgentExecutionContext,
|
|
62
|
+
AgentExecutionResult
|
|
63
|
+
)
|
|
64
|
+
from ..utils.data_models import (
|
|
65
|
+
AgentReasoningTrace,
|
|
66
|
+
SocraticNudge,
|
|
67
|
+
HITLAlert
|
|
68
|
+
)
|
|
69
|
+
except ImportError:
|
|
70
|
+
from wrapper.agent_protocol import (
|
|
71
|
+
AgentAdapter,
|
|
72
|
+
AgentExecutionContext,
|
|
73
|
+
AgentExecutionResult
|
|
74
|
+
)
|
|
75
|
+
from utils.data_models import (
|
|
76
|
+
AgentReasoningTrace,
|
|
77
|
+
SocraticNudge,
|
|
78
|
+
HITLAlert
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class CrewAIAdapter(AgentAdapter):
|
|
83
|
+
"""
|
|
84
|
+
Adapter for CrewAI agents, crews, and tasks.
|
|
85
|
+
|
|
86
|
+
This adapter translates between CrewAI's agent framework and Steward Agent's
|
|
87
|
+
universal monitoring interface.
|
|
88
|
+
|
|
89
|
+
CrewAI-Specific Handling:
|
|
90
|
+
- Extracts reasoning from CrewOutput objects
|
|
91
|
+
- Handles .raw and .content attributes
|
|
92
|
+
- Injects feedback into agent context
|
|
93
|
+
- Extracts role, goal, backstory from agents
|
|
94
|
+
|
|
95
|
+
Attributes:
|
|
96
|
+
logger: Logger instance
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
def __init__(self, logger: Optional[logging.Logger] = None):
|
|
100
|
+
"""
|
|
101
|
+
Initialize CrewAI Adapter.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
logger: Optional logger instance
|
|
105
|
+
"""
|
|
106
|
+
self.logger = logger or logging.getLogger(__name__)
|
|
107
|
+
|
|
108
|
+
if not CREWAI_AVAILABLE:
|
|
109
|
+
self.logger.warning(
|
|
110
|
+
"CrewAI is not installed. CrewAIAdapter will not support any agents. "
|
|
111
|
+
"Install with: pip install crewai"
|
|
112
|
+
)
|
|
113
|
+
else:
|
|
114
|
+
self.logger.debug("CrewAIAdapter initialized with CrewAI support")
|
|
115
|
+
|
|
116
|
+
def supports_agent(self, agent: Any) -> bool:
|
|
117
|
+
"""
|
|
118
|
+
Check if agent is a CrewAI Agent, Crew, or Task.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
agent: Object to check
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
True if agent is from CrewAI framework
|
|
125
|
+
"""
|
|
126
|
+
if not CREWAI_AVAILABLE:
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
is_supported = isinstance(agent, (Agent, CrewAIAgent, Crew, Task))
|
|
130
|
+
|
|
131
|
+
if not is_supported:
|
|
132
|
+
self.logger.debug(
|
|
133
|
+
f"Agent type {type(agent).__name__} is not a CrewAI agent"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
return is_supported
|
|
137
|
+
|
|
138
|
+
def get_execution_methods(self) -> list:
|
|
139
|
+
"""
|
|
140
|
+
Return list of method names that trigger CrewAI agent execution.
|
|
141
|
+
|
|
142
|
+
CrewAI agents use:
|
|
143
|
+
- execute(): Generic execution method
|
|
144
|
+
- kickoff(): Main CrewAI execution method
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
List of method names to monitor: ['execute', 'kickoff']
|
|
148
|
+
"""
|
|
149
|
+
return ['execute', 'kickoff']
|
|
150
|
+
|
|
151
|
+
def extract_reasoning(
|
|
152
|
+
self,
|
|
153
|
+
agent: Any,
|
|
154
|
+
execution_result: Any,
|
|
155
|
+
execution_context: Optional[AgentExecutionContext] = None
|
|
156
|
+
) -> AgentReasoningTrace:
|
|
157
|
+
"""
|
|
158
|
+
Extract reasoning trace from CrewAI execution result.
|
|
159
|
+
|
|
160
|
+
Handles CrewAI-specific output formats:
|
|
161
|
+
- CrewOutput objects (has .raw, .content)
|
|
162
|
+
- TaskOutput objects
|
|
163
|
+
- String outputs
|
|
164
|
+
- Dict outputs
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
agent: CrewAI agent that executed
|
|
168
|
+
execution_result: Result from agent execution
|
|
169
|
+
execution_context: Optional execution context
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
AgentReasoningTrace with extracted information
|
|
173
|
+
"""
|
|
174
|
+
# Extract agent name and type
|
|
175
|
+
agent_name = self._get_agent_name(agent)
|
|
176
|
+
agent_type = self._get_agent_type(agent)
|
|
177
|
+
|
|
178
|
+
# Extract reasoning and output from CrewAI result
|
|
179
|
+
reasoning_text, final_output = self._extract_from_crew_output(execution_result)
|
|
180
|
+
|
|
181
|
+
# Get goal
|
|
182
|
+
goal = ""
|
|
183
|
+
if execution_context:
|
|
184
|
+
goal = execution_context.goal or execution_context.task or ""
|
|
185
|
+
elif hasattr(agent, 'goal'):
|
|
186
|
+
goal = str(agent.goal)
|
|
187
|
+
|
|
188
|
+
# Create reasoning trace
|
|
189
|
+
trace = AgentReasoningTrace(
|
|
190
|
+
agent_name=agent_name,
|
|
191
|
+
agent_type=agent_type,
|
|
192
|
+
reasoning_text=reasoning_text,
|
|
193
|
+
final_output=final_output,
|
|
194
|
+
goal=goal,
|
|
195
|
+
context_information=self._extract_context_info(agent, execution_context)
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
self.logger.debug(
|
|
199
|
+
f"Extracted CrewAI reasoning trace for {agent_name}: "
|
|
200
|
+
f"output_length={len(str(final_output))}"
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
return trace
|
|
204
|
+
|
|
205
|
+
def inject_feedback(
|
|
206
|
+
self,
|
|
207
|
+
agent: Any,
|
|
208
|
+
feedback: Union[SocraticNudge, HITLAlert, str],
|
|
209
|
+
execution_context: Optional[AgentExecutionContext] = None
|
|
210
|
+
) -> None:
|
|
211
|
+
"""
|
|
212
|
+
Inject Steward Agent feedback into CrewAI agent.
|
|
213
|
+
|
|
214
|
+
Strategy:
|
|
215
|
+
1. If agent has context attribute, append feedback
|
|
216
|
+
2. If agent has memory, add to memory
|
|
217
|
+
3. Otherwise, log warning
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
agent: CrewAI agent to inject feedback into
|
|
221
|
+
feedback: Feedback from Steward Agent
|
|
222
|
+
execution_context: Optional execution context
|
|
223
|
+
"""
|
|
224
|
+
feedback_text = self._feedback_to_string(feedback)
|
|
225
|
+
|
|
226
|
+
injected = False
|
|
227
|
+
|
|
228
|
+
# Strategy 1: Agent has context
|
|
229
|
+
if hasattr(agent, 'context') and agent.context is not None:
|
|
230
|
+
if isinstance(agent.context, list):
|
|
231
|
+
agent.context.append(feedback_text)
|
|
232
|
+
injected = True
|
|
233
|
+
self.logger.debug("Feedback injected into CrewAI agent.context")
|
|
234
|
+
elif isinstance(agent.context, str):
|
|
235
|
+
agent.context += f"\n\n{feedback_text}"
|
|
236
|
+
injected = True
|
|
237
|
+
self.logger.debug("Feedback appended to CrewAI agent.context string")
|
|
238
|
+
|
|
239
|
+
# Strategy 2: Agent has memory
|
|
240
|
+
if not injected and hasattr(agent, 'memory'):
|
|
241
|
+
try:
|
|
242
|
+
agent.memory.add(feedback_text)
|
|
243
|
+
injected = True
|
|
244
|
+
self.logger.debug("Feedback added to CrewAI agent.memory")
|
|
245
|
+
except Exception as e:
|
|
246
|
+
self.logger.debug(f"Could not add to agent.memory: {e}")
|
|
247
|
+
|
|
248
|
+
# Fallback: Log warning
|
|
249
|
+
if not injected:
|
|
250
|
+
self.logger.warning(
|
|
251
|
+
f"Could not inject feedback into CrewAI agent {agent_name}. "
|
|
252
|
+
f"Agent has no compatible context or memory attribute."
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
def get_agent_metadata(self, agent: Any) -> Dict[str, Any]:
|
|
256
|
+
"""
|
|
257
|
+
Extract metadata from CrewAI agent.
|
|
258
|
+
|
|
259
|
+
Extracts:
|
|
260
|
+
- role: Agent's role
|
|
261
|
+
- goal: Agent's goal
|
|
262
|
+
- backstory: Agent's backstory
|
|
263
|
+
- verbose: Verbosity setting
|
|
264
|
+
- allow_delegation: Delegation setting
|
|
265
|
+
- tools: Available tools
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
agent: CrewAI agent
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
Dictionary with agent metadata
|
|
272
|
+
"""
|
|
273
|
+
metadata = {
|
|
274
|
+
'framework': 'crewai',
|
|
275
|
+
'adapter': 'CrewAIAdapter',
|
|
276
|
+
'agent_name': self._get_agent_name(agent),
|
|
277
|
+
'agent_type': self._get_agent_type(agent),
|
|
278
|
+
'agent_class': type(agent).__name__,
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
# Extract CrewAI-specific attributes
|
|
282
|
+
if hasattr(agent, 'role'):
|
|
283
|
+
metadata['role'] = str(agent.role)
|
|
284
|
+
if hasattr(agent, 'goal'):
|
|
285
|
+
metadata['goal'] = str(agent.goal)
|
|
286
|
+
if hasattr(agent, 'backstory'):
|
|
287
|
+
metadata['backstory'] = str(agent.backstory)[:200] # Limit length
|
|
288
|
+
if hasattr(agent, 'verbose'):
|
|
289
|
+
metadata['verbose'] = agent.verbose
|
|
290
|
+
if hasattr(agent, 'allow_delegation'):
|
|
291
|
+
metadata['allow_delegation'] = agent.allow_delegation
|
|
292
|
+
if hasattr(agent, 'tools'):
|
|
293
|
+
metadata['tools_count'] = len(agent.tools) if agent.tools else 0
|
|
294
|
+
|
|
295
|
+
self.logger.debug(f"Extracted metadata for CrewAI agent {metadata['agent_name']}")
|
|
296
|
+
|
|
297
|
+
return metadata
|
|
298
|
+
|
|
299
|
+
# ========================================
|
|
300
|
+
# Helper Methods
|
|
301
|
+
# ========================================
|
|
302
|
+
|
|
303
|
+
def _get_agent_name(self, agent: Any) -> str:
|
|
304
|
+
"""Get agent name from CrewAI agent."""
|
|
305
|
+
if hasattr(agent, 'role'):
|
|
306
|
+
return str(agent.role)
|
|
307
|
+
if hasattr(agent, 'name'):
|
|
308
|
+
return str(agent.name)
|
|
309
|
+
return type(agent).__name__
|
|
310
|
+
|
|
311
|
+
def _get_agent_type(self, agent: Any) -> str:
|
|
312
|
+
"""Determine agent type from CrewAI agent."""
|
|
313
|
+
# Check if it's a planner or executor based on role/goal
|
|
314
|
+
if hasattr(agent, 'role'):
|
|
315
|
+
role = str(agent.role).lower()
|
|
316
|
+
if 'plan' in role or 'manager' in role or 'coordinator' in role:
|
|
317
|
+
return 'planner'
|
|
318
|
+
return 'executor'
|
|
319
|
+
return 'generic'
|
|
320
|
+
|
|
321
|
+
def _extract_from_crew_output(self, result: Any) -> tuple[str, str]:
|
|
322
|
+
"""
|
|
323
|
+
Extract reasoning and output from CrewAI result.
|
|
324
|
+
|
|
325
|
+
Handles different CrewAI output formats.
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
Tuple of (reasoning_text, final_output)
|
|
329
|
+
"""
|
|
330
|
+
reasoning_text = ""
|
|
331
|
+
final_output = ""
|
|
332
|
+
|
|
333
|
+
# Case 1: CrewOutput object (has .raw attribute)
|
|
334
|
+
if hasattr(result, 'raw'):
|
|
335
|
+
final_output = str(result.raw)
|
|
336
|
+
reasoning_text = f"CrewAI Output (raw): {final_output}"
|
|
337
|
+
|
|
338
|
+
# Case 2: Has .content attribute
|
|
339
|
+
elif hasattr(result, 'content'):
|
|
340
|
+
final_output = str(result.content)
|
|
341
|
+
reasoning_text = f"CrewAI Output (content): {final_output}"
|
|
342
|
+
|
|
343
|
+
# Case 3: TaskOutput object
|
|
344
|
+
elif hasattr(result, 'output'):
|
|
345
|
+
final_output = str(result.output)
|
|
346
|
+
if hasattr(result, 'description'):
|
|
347
|
+
reasoning_text = f"Task: {result.description}\nOutput: {final_output}"
|
|
348
|
+
else:
|
|
349
|
+
reasoning_text = f"Task Output: {final_output}"
|
|
350
|
+
|
|
351
|
+
# Case 4: Dictionary
|
|
352
|
+
elif isinstance(result, dict):
|
|
353
|
+
final_output = str(result.get('output', result.get('result', str(result))))
|
|
354
|
+
reasoning_text = str(result.get('reasoning', f"CrewAI result: {final_output}"))
|
|
355
|
+
|
|
356
|
+
# Case 5: String or other
|
|
357
|
+
else:
|
|
358
|
+
final_output = str(result)
|
|
359
|
+
reasoning_text = f"CrewAI execution result: {final_output}"
|
|
360
|
+
|
|
361
|
+
return reasoning_text, final_output
|
|
362
|
+
|
|
363
|
+
def _extract_context_info(
|
|
364
|
+
self,
|
|
365
|
+
agent: Any,
|
|
366
|
+
execution_context: Optional[AgentExecutionContext]
|
|
367
|
+
) -> Dict[str, Any]:
|
|
368
|
+
"""Extract context information for reasoning trace."""
|
|
369
|
+
context_info = {
|
|
370
|
+
'adapter': 'CrewAIAdapter',
|
|
371
|
+
'framework': 'crewai',
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if execution_context:
|
|
375
|
+
context_info['execution_context'] = {
|
|
376
|
+
'agent_id': execution_context.agent_id,
|
|
377
|
+
'task': execution_context.task,
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
# Add CrewAI-specific context
|
|
381
|
+
if hasattr(agent, 'role'):
|
|
382
|
+
context_info['agent_role'] = str(agent.role)
|
|
383
|
+
if hasattr(agent, 'goal'):
|
|
384
|
+
context_info['agent_goal'] = str(agent.goal)
|
|
385
|
+
|
|
386
|
+
return context_info
|
|
387
|
+
|
|
388
|
+
def _feedback_to_string(self, feedback: Union[SocraticNudge, HITLAlert, str]) -> str:
|
|
389
|
+
"""Convert feedback to string representation."""
|
|
390
|
+
if isinstance(feedback, str):
|
|
391
|
+
return feedback
|
|
392
|
+
elif isinstance(feedback, SocraticNudge):
|
|
393
|
+
return f"[Steward Agent - Socratic Nudge]\n{feedback.question}"
|
|
394
|
+
elif isinstance(feedback, HITLAlert):
|
|
395
|
+
return f"[Steward Agent - HITL Alert]\n{feedback.alert_message}\nPriority: {feedback.priority}"
|
|
396
|
+
else:
|
|
397
|
+
return str(feedback)
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
__all__ = ['CrewAIAdapter']
|