erdo 0.1.31__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.
- erdo/__init__.py +35 -0
- erdo/_generated/__init__.py +18 -0
- erdo/_generated/actions/__init__.py +34 -0
- erdo/_generated/actions/analysis.py +179 -0
- erdo/_generated/actions/bot.py +186 -0
- erdo/_generated/actions/codeexec.py +199 -0
- erdo/_generated/actions/llm.py +148 -0
- erdo/_generated/actions/memory.py +463 -0
- erdo/_generated/actions/pdfextractor.py +97 -0
- erdo/_generated/actions/resource_definitions.py +296 -0
- erdo/_generated/actions/sqlexec.py +90 -0
- erdo/_generated/actions/utils.py +475 -0
- erdo/_generated/actions/webparser.py +119 -0
- erdo/_generated/actions/websearch.py +85 -0
- erdo/_generated/condition/__init__.py +556 -0
- erdo/_generated/internal.py +51 -0
- erdo/_generated/internal_actions.py +91 -0
- erdo/_generated/parameters.py +17 -0
- erdo/_generated/secrets.py +17 -0
- erdo/_generated/template_functions.py +55 -0
- erdo/_generated/types.py +3907 -0
- erdo/actions/__init__.py +40 -0
- erdo/bot_permissions.py +266 -0
- erdo/cli_entry.py +73 -0
- erdo/conditions/__init__.py +11 -0
- erdo/config/__init__.py +5 -0
- erdo/config/config.py +140 -0
- erdo/formatting.py +279 -0
- erdo/install_cli.py +140 -0
- erdo/integrations.py +131 -0
- erdo/invoke/__init__.py +11 -0
- erdo/invoke/client.py +234 -0
- erdo/invoke/invoke.py +555 -0
- erdo/state.py +376 -0
- erdo/sync/__init__.py +17 -0
- erdo/sync/client.py +95 -0
- erdo/sync/extractor.py +492 -0
- erdo/sync/sync.py +327 -0
- erdo/template.py +136 -0
- erdo/test/__init__.py +41 -0
- erdo/test/evaluate.py +272 -0
- erdo/test/runner.py +263 -0
- erdo/types.py +1431 -0
- erdo-0.1.31.dist-info/METADATA +471 -0
- erdo-0.1.31.dist-info/RECORD +48 -0
- erdo-0.1.31.dist-info/WHEEL +4 -0
- erdo-0.1.31.dist-info/entry_points.txt +2 -0
- erdo-0.1.31.dist-info/licenses/LICENSE +22 -0
erdo/invoke/invoke.py
ADDED
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
"""Main invoke functionality for running agents via the orchestrator."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import Any, Dict, List, Optional, Union
|
|
7
|
+
|
|
8
|
+
from erdo._generated.types import Result
|
|
9
|
+
|
|
10
|
+
from .client import InvokeClient
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class InvokeResult:
|
|
15
|
+
"""Result from a bot invocation.
|
|
16
|
+
|
|
17
|
+
Follows the executor pattern with clean separation:
|
|
18
|
+
- .result: The actual bot output (text/data from messages)
|
|
19
|
+
- .messages: List of message objects with role/content
|
|
20
|
+
- .events: Full list of all events (for debugging/analysis)
|
|
21
|
+
- .steps: Information about executed steps
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
success: bool
|
|
25
|
+
bot_id: Optional[str] = None
|
|
26
|
+
invocation_id: Optional[str] = None
|
|
27
|
+
result: Optional[Result] = None # The actual bot result (types.Result object)
|
|
28
|
+
messages: List[Dict[str, Any]] = field(default_factory=list) # Message objects
|
|
29
|
+
events: List[Dict[str, Any]] = field(default_factory=list) # All raw events
|
|
30
|
+
steps: List[Dict[str, Any]] = field(default_factory=list) # Step execution info
|
|
31
|
+
error: Optional[str] = None
|
|
32
|
+
|
|
33
|
+
def __str__(self) -> str:
|
|
34
|
+
if self.success:
|
|
35
|
+
result_preview = str(self.result)[:100] if self.result else "No result"
|
|
36
|
+
return f"ā
Success (ID: {self.invocation_id})\nResult: {result_preview}"
|
|
37
|
+
else:
|
|
38
|
+
return f"ā Failed: {self.error}"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Invoke:
|
|
42
|
+
"""Main class for invoking agents."""
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
agent: Optional[Any] = None,
|
|
47
|
+
parameters: Optional[Dict[str, Any]] = None,
|
|
48
|
+
dataset_slugs: Optional[list] = None,
|
|
49
|
+
endpoint: Optional[str] = None,
|
|
50
|
+
auth_token: Optional[str] = None,
|
|
51
|
+
stream: bool = False,
|
|
52
|
+
print_events: bool = False,
|
|
53
|
+
):
|
|
54
|
+
"""Initialize and optionally invoke an agent immediately.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
agent: Optional Agent instance to invoke immediately
|
|
58
|
+
parameters: Parameters to pass to the agent
|
|
59
|
+
dataset_slugs: Dataset slugs to include (e.g. ["my-dataset"] or ["org.my-dataset"])
|
|
60
|
+
endpoint: API endpoint URL
|
|
61
|
+
auth_token: Authentication token
|
|
62
|
+
stream: Whether to stream events
|
|
63
|
+
print_events: Whether to print events as they arrive
|
|
64
|
+
"""
|
|
65
|
+
self.client = InvokeClient(endpoint=endpoint, auth_token=auth_token)
|
|
66
|
+
self.print_events = print_events
|
|
67
|
+
self.result = None
|
|
68
|
+
|
|
69
|
+
# If an agent is provided, invoke it immediately
|
|
70
|
+
if agent:
|
|
71
|
+
bot_key = getattr(agent, "key", None)
|
|
72
|
+
if not bot_key:
|
|
73
|
+
raise ValueError("Agent must have a 'key' attribute for invocation")
|
|
74
|
+
|
|
75
|
+
self.result = self.invoke_by_key(
|
|
76
|
+
bot_key,
|
|
77
|
+
parameters=parameters,
|
|
78
|
+
dataset_slugs=dataset_slugs,
|
|
79
|
+
stream=stream,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def invoke_agent(
|
|
83
|
+
self,
|
|
84
|
+
agent: Any,
|
|
85
|
+
parameters: Optional[Dict[str, Any]] = None,
|
|
86
|
+
dataset_slugs: Optional[list] = None,
|
|
87
|
+
stream: bool = False,
|
|
88
|
+
) -> InvokeResult:
|
|
89
|
+
"""Invoke an agent instance.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
agent: Agent instance with a 'key' attribute
|
|
93
|
+
parameters: Parameters to pass to the agent
|
|
94
|
+
dataset_slugs: Dataset slugs to include (e.g. ["my-dataset"] or ["org.my-dataset"])
|
|
95
|
+
stream: Whether to stream events
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
InvokeResult with the outcome
|
|
99
|
+
"""
|
|
100
|
+
bot_key = getattr(agent, "key", None)
|
|
101
|
+
if not bot_key:
|
|
102
|
+
raise ValueError("Agent must have a 'key' attribute for invocation")
|
|
103
|
+
|
|
104
|
+
return self.invoke_by_key(
|
|
105
|
+
bot_key, parameters=parameters, dataset_slugs=dataset_slugs, stream=stream
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
def invoke_by_key(
|
|
109
|
+
self,
|
|
110
|
+
bot_key: str,
|
|
111
|
+
messages: Optional[List[Dict[str, str]]] = None,
|
|
112
|
+
parameters: Optional[Dict[str, Any]] = None,
|
|
113
|
+
dataset_slugs: Optional[list] = None,
|
|
114
|
+
mode: Optional[Union[str, Dict[str, Any]]] = None,
|
|
115
|
+
manual_mocks: Optional[Dict[str, Dict[str, Any]]] = None,
|
|
116
|
+
stream: bool = False,
|
|
117
|
+
output_format: str = "events",
|
|
118
|
+
verbose: bool = False,
|
|
119
|
+
) -> InvokeResult:
|
|
120
|
+
"""Invoke a bot by its key.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
bot_key: Bot key (e.g., "erdo.data-analyzer")
|
|
124
|
+
messages: Messages in format [{"role": "user", "content": "..."}]
|
|
125
|
+
parameters: Parameters to pass to the bot
|
|
126
|
+
dataset_slugs: Dataset slugs to include (e.g. ["my-dataset"] or ["org.my-dataset"])
|
|
127
|
+
mode: Invocation mode - string: "live|replay|manual" OR dict: {"mode": "replay", "refresh": true}
|
|
128
|
+
manual_mocks: Manual mock responses for mode="manual" (step_path -> mock response)
|
|
129
|
+
stream: Whether to stream events
|
|
130
|
+
output_format: Output format: "events" (raw), "text" (formatted), "json" (summary)
|
|
131
|
+
verbose: Show detailed steps (only for text format)
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
InvokeResult with the outcome
|
|
135
|
+
"""
|
|
136
|
+
try:
|
|
137
|
+
response = self.client.invoke_bot(
|
|
138
|
+
bot_key,
|
|
139
|
+
messages=messages,
|
|
140
|
+
parameters=parameters,
|
|
141
|
+
dataset_slugs=dataset_slugs,
|
|
142
|
+
mode=mode,
|
|
143
|
+
manual_mocks=manual_mocks,
|
|
144
|
+
stream=stream,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
if stream:
|
|
148
|
+
# Process SSE events
|
|
149
|
+
events = []
|
|
150
|
+
invocation_id = None
|
|
151
|
+
|
|
152
|
+
# Type guard: response should be SSEClient when stream=True
|
|
153
|
+
if not isinstance(response, dict):
|
|
154
|
+
# For formatted output, print as we stream
|
|
155
|
+
if output_format in ["text", "json"] and not self.print_events:
|
|
156
|
+
bot_name_printed = False
|
|
157
|
+
completed_steps = set()
|
|
158
|
+
step_names = {} # Map to track step keys
|
|
159
|
+
printed_content_ids = (
|
|
160
|
+
set()
|
|
161
|
+
) # Track which message content we've printed
|
|
162
|
+
|
|
163
|
+
for event in response.events():
|
|
164
|
+
if not event:
|
|
165
|
+
continue
|
|
166
|
+
events.append(event)
|
|
167
|
+
|
|
168
|
+
# Extract payload and metadata
|
|
169
|
+
payload = event.get("payload", {})
|
|
170
|
+
metadata = event.get("metadata", {})
|
|
171
|
+
status = (
|
|
172
|
+
payload.get("status")
|
|
173
|
+
if isinstance(payload, dict)
|
|
174
|
+
else None
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Extract invocation ID and bot name from payload
|
|
178
|
+
if isinstance(payload, dict):
|
|
179
|
+
if "invocation_id" in payload and not invocation_id:
|
|
180
|
+
invocation_id = payload["invocation_id"]
|
|
181
|
+
if "bot_name" in payload and not bot_name_printed:
|
|
182
|
+
bot_name = payload["bot_name"]
|
|
183
|
+
if output_format == "text":
|
|
184
|
+
print(f"Bot: {bot_name}")
|
|
185
|
+
print(
|
|
186
|
+
f"Invocation ID: {invocation_id or 'N/A'}"
|
|
187
|
+
)
|
|
188
|
+
print() # Empty line before steps start
|
|
189
|
+
bot_name_printed = True
|
|
190
|
+
|
|
191
|
+
# Track and display step info (ONLY in verbose mode)
|
|
192
|
+
# step_info events have both key and action_type in payload
|
|
193
|
+
if (
|
|
194
|
+
verbose
|
|
195
|
+
and output_format == "text"
|
|
196
|
+
and isinstance(payload, dict)
|
|
197
|
+
):
|
|
198
|
+
if "key" in payload and "action_type" in payload:
|
|
199
|
+
# This is a step_info event - show "āø" here if visible
|
|
200
|
+
step_key = payload["key"]
|
|
201
|
+
action_type = payload["action_type"]
|
|
202
|
+
step_names[step_key] = action_type
|
|
203
|
+
|
|
204
|
+
# Show step start on step_info event if visible
|
|
205
|
+
if metadata.get("user_visibility") == "visible":
|
|
206
|
+
print(f"āø {step_key} ({action_type})")
|
|
207
|
+
|
|
208
|
+
# Handle step finished events (check status in payload)
|
|
209
|
+
# We look for the most recent step from step_names (ONLY in verbose mode)
|
|
210
|
+
if (
|
|
211
|
+
verbose
|
|
212
|
+
and output_format == "text"
|
|
213
|
+
and status == "step finished"
|
|
214
|
+
):
|
|
215
|
+
if metadata.get("user_visibility") == "visible":
|
|
216
|
+
# Find the last step that we haven't marked complete yet
|
|
217
|
+
for step_key in reversed(list(step_names.keys())):
|
|
218
|
+
if step_key not in completed_steps:
|
|
219
|
+
print(f"ā {step_key}")
|
|
220
|
+
completed_steps.add(step_key)
|
|
221
|
+
break
|
|
222
|
+
|
|
223
|
+
# Print message content as it streams
|
|
224
|
+
# ONLY print if:
|
|
225
|
+
# 1. user_visibility is "visible"
|
|
226
|
+
# 2. Has message_content_id (actual message content, not fragments)
|
|
227
|
+
# 3. content_type is "text" (not "json" or other types)
|
|
228
|
+
# 4. Haven't already printed chunks for this content_id
|
|
229
|
+
if (
|
|
230
|
+
output_format == "text"
|
|
231
|
+
and isinstance(payload, str)
|
|
232
|
+
and len(payload) > 0
|
|
233
|
+
and isinstance(metadata, dict)
|
|
234
|
+
and metadata.get("user_visibility") == "visible"
|
|
235
|
+
and metadata.get(
|
|
236
|
+
"message_content_id"
|
|
237
|
+
) # Must be message content
|
|
238
|
+
and metadata.get("content_type")
|
|
239
|
+
== "text" # Only plain text, not JSON
|
|
240
|
+
):
|
|
241
|
+
content_id = metadata.get("message_content_id")
|
|
242
|
+
# If this is a full message (long) and we've already printed chunks, skip
|
|
243
|
+
if (
|
|
244
|
+
len(payload) > 20
|
|
245
|
+
and content_id in printed_content_ids
|
|
246
|
+
):
|
|
247
|
+
# This is a duplicate full message after streaming chunks
|
|
248
|
+
pass
|
|
249
|
+
else:
|
|
250
|
+
print(payload, end="", flush=True)
|
|
251
|
+
printed_content_ids.add(content_id)
|
|
252
|
+
else:
|
|
253
|
+
# For raw events or print_events mode, just collect
|
|
254
|
+
for event in response.events():
|
|
255
|
+
if not event:
|
|
256
|
+
continue
|
|
257
|
+
events.append(event)
|
|
258
|
+
|
|
259
|
+
if self.print_events:
|
|
260
|
+
self._print_event(event)
|
|
261
|
+
|
|
262
|
+
# Extract invocation ID from events
|
|
263
|
+
if "invocation_id" in event:
|
|
264
|
+
invocation_id = event["invocation_id"]
|
|
265
|
+
|
|
266
|
+
# Extract structured data from events
|
|
267
|
+
result_data = self._extract_result_data(events)
|
|
268
|
+
|
|
269
|
+
return InvokeResult(
|
|
270
|
+
success=True,
|
|
271
|
+
bot_id=bot_key,
|
|
272
|
+
invocation_id=invocation_id,
|
|
273
|
+
result=result_data["result"],
|
|
274
|
+
messages=result_data["messages"],
|
|
275
|
+
steps=result_data["steps"],
|
|
276
|
+
events=events,
|
|
277
|
+
)
|
|
278
|
+
else:
|
|
279
|
+
# Non-streaming response - response is a dict with 'events' key
|
|
280
|
+
response_dict = response if isinstance(response, dict) else {}
|
|
281
|
+
# Extract the events list from the response
|
|
282
|
+
events = response_dict.get("events", [])
|
|
283
|
+
|
|
284
|
+
# Extract structured data from events
|
|
285
|
+
result_data = self._extract_result_data(events)
|
|
286
|
+
|
|
287
|
+
return InvokeResult(
|
|
288
|
+
success=True,
|
|
289
|
+
bot_id=bot_key,
|
|
290
|
+
result=result_data["result"],
|
|
291
|
+
messages=result_data["messages"],
|
|
292
|
+
steps=result_data["steps"],
|
|
293
|
+
events=events,
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
except Exception as e:
|
|
297
|
+
return InvokeResult(success=False, bot_id=bot_key, error=str(e))
|
|
298
|
+
|
|
299
|
+
def _extract_result_data(self, events: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
300
|
+
"""Extract structured data from events.
|
|
301
|
+
|
|
302
|
+
Args:
|
|
303
|
+
events: List of events from the invocation
|
|
304
|
+
|
|
305
|
+
Returns:
|
|
306
|
+
Dict with:
|
|
307
|
+
- result: The final Result object {status, parameters, output, message, error}
|
|
308
|
+
- messages: List of message objects {role, content}
|
|
309
|
+
- steps: List of step execution info {key, action, status}
|
|
310
|
+
"""
|
|
311
|
+
messages = []
|
|
312
|
+
steps = []
|
|
313
|
+
steps_seen = set()
|
|
314
|
+
final_result = None
|
|
315
|
+
|
|
316
|
+
# Iterate through ALL events to collect messages and steps
|
|
317
|
+
for event in events:
|
|
318
|
+
if not event:
|
|
319
|
+
continue
|
|
320
|
+
|
|
321
|
+
payload = event.get("payload", {})
|
|
322
|
+
metadata = event.get("metadata", {})
|
|
323
|
+
|
|
324
|
+
# Handle None values explicitly
|
|
325
|
+
if payload is None:
|
|
326
|
+
payload = {}
|
|
327
|
+
if metadata is None:
|
|
328
|
+
metadata = {}
|
|
329
|
+
|
|
330
|
+
# Extract step information
|
|
331
|
+
if (
|
|
332
|
+
isinstance(payload, dict)
|
|
333
|
+
and "action_type" in payload
|
|
334
|
+
and "key" in payload
|
|
335
|
+
):
|
|
336
|
+
step_key = payload["key"]
|
|
337
|
+
if step_key not in steps_seen:
|
|
338
|
+
steps_seen.add(step_key)
|
|
339
|
+
steps.append(
|
|
340
|
+
{
|
|
341
|
+
"key": step_key,
|
|
342
|
+
"action": payload["action_type"],
|
|
343
|
+
"status": "completed",
|
|
344
|
+
}
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
# Extract messages from ANY event with output.content
|
|
348
|
+
# This captures messages from all steps including sub-agents
|
|
349
|
+
# ONLY collect from output.content (final complete messages)
|
|
350
|
+
# NOT from streaming chunks (those have message_content_id)
|
|
351
|
+
if (
|
|
352
|
+
isinstance(payload, dict)
|
|
353
|
+
and "output" in payload
|
|
354
|
+
and metadata.get("user_visibility") == "visible"
|
|
355
|
+
):
|
|
356
|
+
output = payload.get("output")
|
|
357
|
+
if isinstance(output, dict) and "content" in output:
|
|
358
|
+
content_array = output["content"]
|
|
359
|
+
if isinstance(content_array, list):
|
|
360
|
+
for item in content_array:
|
|
361
|
+
if (
|
|
362
|
+
isinstance(item, dict)
|
|
363
|
+
and item.get("content_type") == "text"
|
|
364
|
+
):
|
|
365
|
+
# Extract as assistant message (or check for role in metadata)
|
|
366
|
+
role = metadata.get("role", "assistant")
|
|
367
|
+
messages.append(
|
|
368
|
+
{"role": role, "content": item.get("content", "")}
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
# Keep track of final result (last one with status + output)
|
|
372
|
+
if (
|
|
373
|
+
isinstance(payload, dict)
|
|
374
|
+
and "status" in payload
|
|
375
|
+
and "output" in payload
|
|
376
|
+
):
|
|
377
|
+
# Create Result object from the payload
|
|
378
|
+
final_result = Result(
|
|
379
|
+
status=payload.get("status"),
|
|
380
|
+
parameters=payload.get("parameters"),
|
|
381
|
+
output=payload.get("output"),
|
|
382
|
+
message=payload.get("message"),
|
|
383
|
+
error=payload.get("error"),
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
return {
|
|
387
|
+
"result": final_result,
|
|
388
|
+
"messages": messages,
|
|
389
|
+
"steps": steps,
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
def _print_event(self, event: Dict[str, Any]):
|
|
393
|
+
"""Print an event in a readable format."""
|
|
394
|
+
event_type = event.get("type", "unknown")
|
|
395
|
+
|
|
396
|
+
if event_type == "step_started":
|
|
397
|
+
step_name = event.get("step_name", "Unknown step")
|
|
398
|
+
print(f"š Step started: {step_name}")
|
|
399
|
+
elif event_type == "step_completed":
|
|
400
|
+
step_name = event.get("step_name", "Unknown step")
|
|
401
|
+
print(f"ā
Step completed: {step_name}")
|
|
402
|
+
elif event_type == "llm_chunk":
|
|
403
|
+
content = event.get("content", "")
|
|
404
|
+
print(content, end="", flush=True)
|
|
405
|
+
elif event_type == "invocation_completed":
|
|
406
|
+
print("\n⨠Invocation completed")
|
|
407
|
+
elif event_type == "error":
|
|
408
|
+
error = event.get("error", "Unknown error")
|
|
409
|
+
print(f"ā Error: {error}")
|
|
410
|
+
else:
|
|
411
|
+
# Generic event printing
|
|
412
|
+
print(f"š” {event_type}: {json.dumps(event, indent=2)}")
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
# Convenience functions
|
|
416
|
+
def invoke(
|
|
417
|
+
bot_key: str,
|
|
418
|
+
messages: Optional[List[Dict[str, str]]] = None,
|
|
419
|
+
parameters: Optional[Dict[str, Any]] = None,
|
|
420
|
+
datasets: Optional[list] = None,
|
|
421
|
+
mode: Optional[Union[str, Dict[str, Any]]] = None,
|
|
422
|
+
manual_mocks: Optional[Dict[str, Dict[str, Any]]] = None,
|
|
423
|
+
stream: bool = False,
|
|
424
|
+
output_format: str = "events",
|
|
425
|
+
verbose: bool = False,
|
|
426
|
+
print_events: bool = False,
|
|
427
|
+
**kwargs,
|
|
428
|
+
) -> InvokeResult:
|
|
429
|
+
"""Invoke a bot with a clean API.
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
bot_key: Bot key (e.g., "erdo.data-analyzer")
|
|
433
|
+
messages: Messages in format [{"role": "user", "content": "..."}]
|
|
434
|
+
parameters: Parameters to pass to the bot
|
|
435
|
+
datasets: Dataset slugs to include (e.g. ["my-dataset"] or ["org.my-dataset"])
|
|
436
|
+
mode: Invocation mode - string: "live|replay|manual" OR dict: {"mode": "replay", "refresh": true}
|
|
437
|
+
manual_mocks: Manual mock responses for mode="manual" (step_path -> mock response)
|
|
438
|
+
stream: Whether to stream events
|
|
439
|
+
output_format: Output format: "events" (raw), "text" (formatted), "json" (summary)
|
|
440
|
+
verbose: Show detailed steps (only for text format)
|
|
441
|
+
print_events: Whether to print events
|
|
442
|
+
**kwargs: Additional arguments (endpoint, auth_token)
|
|
443
|
+
|
|
444
|
+
Returns:
|
|
445
|
+
InvokeResult with formatted result in response.result
|
|
446
|
+
|
|
447
|
+
Example:
|
|
448
|
+
>>> from erdo import invoke
|
|
449
|
+
>>>
|
|
450
|
+
>>> # Simple replay mode
|
|
451
|
+
>>> response = invoke("my_agent", messages=[...], mode="replay")
|
|
452
|
+
>>>
|
|
453
|
+
>>> # Replay mode with refresh (bypass cache)
|
|
454
|
+
>>> response = invoke("my_agent", messages=[...], mode={"mode": "replay", "refresh": True})
|
|
455
|
+
>>>
|
|
456
|
+
>>> # Manual mode with mocks
|
|
457
|
+
>>> response = invoke("my_agent", messages=[...], mode="manual",
|
|
458
|
+
... manual_mocks={"llm.message": {"status": "success", "output": {"content": "Mocked"}}})
|
|
459
|
+
"""
|
|
460
|
+
# Check ERDO_REFRESH environment variable
|
|
461
|
+
# If set and mode is "replay" (string), convert to dict with refresh=True
|
|
462
|
+
if os.environ.get("ERDO_REFRESH") == "1" and mode == "replay":
|
|
463
|
+
mode = {"mode": "replay", "refresh": True}
|
|
464
|
+
|
|
465
|
+
return invoke_by_key(
|
|
466
|
+
bot_key=bot_key,
|
|
467
|
+
messages=messages,
|
|
468
|
+
parameters=parameters,
|
|
469
|
+
dataset_slugs=datasets,
|
|
470
|
+
mode=mode,
|
|
471
|
+
manual_mocks=manual_mocks,
|
|
472
|
+
stream=stream,
|
|
473
|
+
output_format=output_format,
|
|
474
|
+
verbose=verbose,
|
|
475
|
+
print_events=print_events,
|
|
476
|
+
**kwargs,
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def invoke_agent(
|
|
481
|
+
agent: Any,
|
|
482
|
+
parameters: Optional[Dict[str, Any]] = None,
|
|
483
|
+
dataset_slugs: Optional[list] = None,
|
|
484
|
+
stream: bool = False,
|
|
485
|
+
print_events: bool = False,
|
|
486
|
+
**kwargs,
|
|
487
|
+
) -> InvokeResult:
|
|
488
|
+
"""Invoke an agent instance.
|
|
489
|
+
|
|
490
|
+
Args:
|
|
491
|
+
agent: Agent instance with a 'key' attribute
|
|
492
|
+
parameters: Parameters to pass to the agent
|
|
493
|
+
dataset_slugs: Dataset slugs to include (e.g. ["my-dataset"] or ["org.my-dataset"])
|
|
494
|
+
stream: Whether to stream events
|
|
495
|
+
print_events: Whether to print events
|
|
496
|
+
**kwargs: Additional arguments (endpoint, auth_token)
|
|
497
|
+
|
|
498
|
+
Returns:
|
|
499
|
+
InvokeResult with the outcome
|
|
500
|
+
"""
|
|
501
|
+
invoke = Invoke(
|
|
502
|
+
endpoint=kwargs.get("endpoint"),
|
|
503
|
+
auth_token=kwargs.get("auth_token"),
|
|
504
|
+
print_events=print_events,
|
|
505
|
+
)
|
|
506
|
+
return invoke.invoke_agent(agent, parameters, dataset_slugs, stream)
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def invoke_by_key(
|
|
510
|
+
bot_key: str,
|
|
511
|
+
messages: Optional[List[Dict[str, str]]] = None,
|
|
512
|
+
parameters: Optional[Dict[str, Any]] = None,
|
|
513
|
+
dataset_slugs: Optional[list] = None,
|
|
514
|
+
mode: Optional[Union[str, Dict[str, Any]]] = None,
|
|
515
|
+
manual_mocks: Optional[Dict[str, Dict[str, Any]]] = None,
|
|
516
|
+
stream: bool = False,
|
|
517
|
+
output_format: str = "events",
|
|
518
|
+
verbose: bool = False,
|
|
519
|
+
print_events: bool = False,
|
|
520
|
+
**kwargs,
|
|
521
|
+
) -> InvokeResult:
|
|
522
|
+
"""Invoke a bot by its key.
|
|
523
|
+
|
|
524
|
+
Args:
|
|
525
|
+
bot_key: Bot key (e.g., "erdo.data-analyzer")
|
|
526
|
+
messages: Messages in format [{"role": "user", "content": "..."}]
|
|
527
|
+
parameters: Parameters to pass to the bot
|
|
528
|
+
dataset_slugs: Dataset slugs to include (e.g. ["my-dataset"] or ["org.my-dataset"])
|
|
529
|
+
mode: Invocation mode - string: "live|replay|manual" OR dict: {"mode": "replay", "refresh": true}
|
|
530
|
+
manual_mocks: Manual mock responses for mode="manual" (step_path -> mock response)
|
|
531
|
+
stream: Whether to stream events
|
|
532
|
+
output_format: Output format: "events" (raw), "text" (formatted), "json" (summary)
|
|
533
|
+
verbose: Show detailed steps (only for text format)
|
|
534
|
+
print_events: Whether to print events
|
|
535
|
+
**kwargs: Additional arguments (endpoint, auth_token)
|
|
536
|
+
|
|
537
|
+
Returns:
|
|
538
|
+
InvokeResult with the outcome
|
|
539
|
+
"""
|
|
540
|
+
invoke = Invoke(
|
|
541
|
+
endpoint=kwargs.get("endpoint"),
|
|
542
|
+
auth_token=kwargs.get("auth_token"),
|
|
543
|
+
print_events=print_events,
|
|
544
|
+
)
|
|
545
|
+
return invoke.invoke_by_key(
|
|
546
|
+
bot_key,
|
|
547
|
+
messages,
|
|
548
|
+
parameters,
|
|
549
|
+
dataset_slugs,
|
|
550
|
+
mode,
|
|
551
|
+
manual_mocks,
|
|
552
|
+
stream,
|
|
553
|
+
output_format,
|
|
554
|
+
verbose,
|
|
555
|
+
)
|