dacp 0.3.3__py3-none-any.whl → 0.3.4__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 +1 -1
- dacp/api.py +365 -0
- dacp/cli.py +249 -0
- dacp/intelligence.py +10 -28
- dacp/json_parser.py +47 -49
- dacp/logging_config.py +1 -3
- dacp/orchestrator.py +10 -28
- dacp/tools.py +1 -3
- dacp/workflow.py +30 -25
- dacp/workflow_runtime.py +148 -110
- {dacp-0.3.3.dist-info → dacp-0.3.4.dist-info}/METADATA +8 -3
- dacp-0.3.4.dist-info/RECORD +21 -0
- dacp-0.3.4.dist-info/entry_points.txt +2 -0
- dacp-0.3.3.dist-info/RECORD +0 -18
- {dacp-0.3.3.dist-info → dacp-0.3.4.dist-info}/WHEEL +0 -0
- {dacp-0.3.3.dist-info → dacp-0.3.4.dist-info}/licenses/LICENSE +0 -0
- {dacp-0.3.3.dist-info → dacp-0.3.4.dist-info}/top_level.txt +0 -0
dacp/workflow_runtime.py
CHANGED
@@ -20,6 +20,7 @@ logger = logging.getLogger("dacp.workflow_runtime")
|
|
20
20
|
|
21
21
|
class TaskStatus(Enum):
|
22
22
|
"""Task execution status."""
|
23
|
+
|
23
24
|
PENDING = "pending"
|
24
25
|
RUNNING = "running"
|
25
26
|
COMPLETED = "completed"
|
@@ -30,6 +31,7 @@ class TaskStatus(Enum):
|
|
30
31
|
@dataclass
|
31
32
|
class TaskExecution:
|
32
33
|
"""Represents a task execution instance."""
|
34
|
+
|
33
35
|
id: str
|
34
36
|
workflow_id: str
|
35
37
|
step_id: str
|
@@ -66,6 +68,7 @@ class TaskExecution:
|
|
66
68
|
@dataclass
|
67
69
|
class RegisteredAgent:
|
68
70
|
"""Represents a registered agent in the registry."""
|
71
|
+
|
69
72
|
id: str
|
70
73
|
agent_instance: Any
|
71
74
|
spec_file: Optional[str] = None
|
@@ -88,24 +91,24 @@ class RegisteredAgent:
|
|
88
91
|
class AgentRegistry:
|
89
92
|
"""Registry for managing agent instances."""
|
90
93
|
|
91
|
-
def __init__(self):
|
94
|
+
def __init__(self) -> None:
|
92
95
|
self.agents: Dict[str, RegisteredAgent] = {}
|
93
96
|
|
94
97
|
def register_agent(
|
95
|
-
self,
|
96
|
-
agent_id: str,
|
97
|
-
agent_instance: Any,
|
98
|
+
self,
|
99
|
+
agent_id: str,
|
100
|
+
agent_instance: Any,
|
98
101
|
spec_file: Optional[str] = None,
|
99
|
-
metadata: Optional[Dict[str, Any]] = None
|
102
|
+
metadata: Optional[Dict[str, Any]] = None,
|
100
103
|
) -> None:
|
101
104
|
"""Register an agent instance."""
|
102
105
|
registered_agent = RegisteredAgent(
|
103
106
|
id=agent_id,
|
104
107
|
agent_instance=agent_instance,
|
105
108
|
spec_file=spec_file,
|
106
|
-
metadata=metadata or {}
|
109
|
+
metadata=metadata or {},
|
107
110
|
)
|
108
|
-
|
111
|
+
|
109
112
|
self.agents[agent_id] = registered_agent
|
110
113
|
logger.info(f"🤖 Agent '{agent_id}' registered in registry")
|
111
114
|
|
@@ -138,7 +141,7 @@ class AgentRegistry:
|
|
138
141
|
class TaskRegistry:
|
139
142
|
"""Registry for managing task executions."""
|
140
143
|
|
141
|
-
def __init__(self):
|
144
|
+
def __init__(self) -> None:
|
142
145
|
self.tasks: Dict[str, TaskExecution] = {}
|
143
146
|
self.workflow_tasks: Dict[str, List[str]] = {} # workflow_id -> task_ids
|
144
147
|
|
@@ -148,52 +151,54 @@ class TaskRegistry:
|
|
148
151
|
step_id: str,
|
149
152
|
agent_id: str,
|
150
153
|
task_name: str,
|
151
|
-
input_data: Dict[str, Any]
|
154
|
+
input_data: Dict[str, Any],
|
152
155
|
) -> str:
|
153
156
|
"""Create a new task execution."""
|
154
157
|
task_id = str(uuid.uuid4())
|
155
|
-
|
158
|
+
|
156
159
|
task = TaskExecution(
|
157
160
|
id=task_id,
|
158
161
|
workflow_id=workflow_id,
|
159
162
|
step_id=step_id,
|
160
163
|
agent_id=agent_id,
|
161
164
|
task_name=task_name,
|
162
|
-
input_data=input_data
|
165
|
+
input_data=input_data,
|
163
166
|
)
|
164
|
-
|
167
|
+
|
165
168
|
self.tasks[task_id] = task
|
166
|
-
|
169
|
+
|
167
170
|
# Add to workflow tasks
|
168
171
|
if workflow_id not in self.workflow_tasks:
|
169
172
|
self.workflow_tasks[workflow_id] = []
|
170
173
|
self.workflow_tasks[workflow_id].append(task_id)
|
171
|
-
|
172
|
-
logger.info(
|
174
|
+
|
175
|
+
logger.info(
|
176
|
+
f"📋 Task '{task_id}' created for agent '{agent_id}' in workflow '{workflow_id}'"
|
177
|
+
)
|
173
178
|
return task_id
|
174
179
|
|
175
180
|
def get_task(self, task_id: str) -> Optional[TaskExecution]:
|
176
181
|
"""Get a task by ID."""
|
177
182
|
return self.tasks.get(task_id)
|
178
183
|
|
179
|
-
def update_task_status(self, task_id: str, status: TaskStatus, **kwargs) -> bool:
|
184
|
+
def update_task_status(self, task_id: str, status: TaskStatus, **kwargs: Any) -> bool:
|
180
185
|
"""Update task status and optional fields."""
|
181
186
|
if task_id not in self.tasks:
|
182
187
|
return False
|
183
|
-
|
188
|
+
|
184
189
|
task = self.tasks[task_id]
|
185
190
|
task.status = status
|
186
|
-
|
191
|
+
|
187
192
|
# Update optional fields
|
188
193
|
for key, value in kwargs.items():
|
189
194
|
if hasattr(task, key):
|
190
195
|
setattr(task, key, value)
|
191
|
-
|
196
|
+
|
192
197
|
# Calculate duration if completed
|
193
198
|
if status in [TaskStatus.COMPLETED, TaskStatus.FAILED] and task.started_at:
|
194
199
|
task.completed_at = time.time()
|
195
200
|
task.duration = task.completed_at - task.started_at
|
196
|
-
|
201
|
+
|
197
202
|
logger.info(f"📊 Task '{task_id}' status updated to {status.value}")
|
198
203
|
return True
|
199
204
|
|
@@ -204,26 +209,26 @@ class TaskRegistry:
|
|
204
209
|
|
205
210
|
def get_task_summary(self) -> Dict[str, Any]:
|
206
211
|
"""Get summary of all tasks."""
|
207
|
-
status_counts = {}
|
212
|
+
status_counts: Dict[str, int] = {}
|
208
213
|
for task in self.tasks.values():
|
209
214
|
status = task.status.value
|
210
215
|
status_counts[status] = status_counts.get(status, 0) + 1
|
211
|
-
|
216
|
+
|
212
217
|
return {
|
213
218
|
"total_tasks": len(self.tasks),
|
214
219
|
"status_counts": status_counts,
|
215
|
-
"workflows": len(self.workflow_tasks)
|
220
|
+
"workflows": len(self.workflow_tasks),
|
216
221
|
}
|
217
222
|
|
218
223
|
|
219
224
|
class WorkflowRuntime:
|
220
225
|
"""DACP Workflow Runtime - Executes workflows from workflow.yaml"""
|
221
226
|
|
222
|
-
def __init__(self, orchestrator=None):
|
227
|
+
def __init__(self, orchestrator: Optional[Any] = None) -> None:
|
223
228
|
self.orchestrator = orchestrator
|
224
229
|
self.agent_registry = AgentRegistry()
|
225
230
|
self.task_registry = TaskRegistry()
|
226
|
-
self.workflow_config = {}
|
231
|
+
self.workflow_config: Dict[str, Any] = {}
|
227
232
|
self.active_workflows: Dict[str, Dict[str, Any]] = {}
|
228
233
|
|
229
234
|
def load_workflow_config(self, config_path: str) -> None:
|
@@ -231,10 +236,10 @@ class WorkflowRuntime:
|
|
231
236
|
config_file = Path(config_path)
|
232
237
|
if not config_file.exists():
|
233
238
|
raise FileNotFoundError(f"Workflow config file not found: {config_path}")
|
234
|
-
|
235
|
-
with open(config_file,
|
239
|
+
|
240
|
+
with open(config_file, "r") as f:
|
236
241
|
self.workflow_config = yaml.safe_load(f)
|
237
|
-
|
242
|
+
|
238
243
|
logger.info(f"📁 Loaded workflow config from {config_path}")
|
239
244
|
logger.info(f"📋 Found {len(self.workflow_config.get('workflows', {}))} workflows")
|
240
245
|
|
@@ -242,40 +247,42 @@ class WorkflowRuntime:
|
|
242
247
|
"""Register an agent instance based on workflow config."""
|
243
248
|
# Find agent spec in config
|
244
249
|
agent_spec = None
|
245
|
-
for agent_config in self.workflow_config.get(
|
246
|
-
if agent_config[
|
247
|
-
agent_spec = agent_config.get(
|
250
|
+
for agent_config in self.workflow_config.get("agents", []):
|
251
|
+
if agent_config["id"] == agent_id:
|
252
|
+
agent_spec = agent_config.get("spec")
|
248
253
|
break
|
249
|
-
|
254
|
+
|
250
255
|
self.agent_registry.register_agent(
|
251
256
|
agent_id=agent_id,
|
252
257
|
agent_instance=agent_instance,
|
253
258
|
spec_file=agent_spec,
|
254
|
-
metadata={"config_based": True}
|
259
|
+
metadata={"config_based": True},
|
255
260
|
)
|
256
261
|
|
257
|
-
def execute_workflow(
|
262
|
+
def execute_workflow(
|
263
|
+
self, workflow_name: str, initial_input: Optional[Dict[str, Any]] = None
|
264
|
+
) -> str:
|
258
265
|
"""Execute a workflow by name."""
|
259
|
-
if workflow_name not in self.workflow_config.get(
|
266
|
+
if workflow_name not in self.workflow_config.get("workflows", {}):
|
260
267
|
raise ValueError(f"Workflow '{workflow_name}' not found in config")
|
261
|
-
|
262
|
-
workflow_def = self.workflow_config[
|
268
|
+
|
269
|
+
workflow_def = self.workflow_config["workflows"][workflow_name]
|
263
270
|
workflow_id = str(uuid.uuid4())
|
264
|
-
|
271
|
+
|
265
272
|
logger.info(f"🚀 Starting workflow '{workflow_name}' with ID '{workflow_id}'")
|
266
|
-
|
273
|
+
|
267
274
|
# Initialize workflow state
|
268
275
|
self.active_workflows[workflow_id] = {
|
269
276
|
"name": workflow_name,
|
270
277
|
"definition": workflow_def,
|
271
278
|
"current_step": 0,
|
272
|
-
"context": initial_input or {},
|
273
|
-
"started_at": time.time()
|
279
|
+
"context": {"input": initial_input or {}},
|
280
|
+
"started_at": time.time(),
|
274
281
|
}
|
275
|
-
|
282
|
+
|
276
283
|
# Execute first step
|
277
284
|
self._execute_workflow_step(workflow_id, 0)
|
278
|
-
|
285
|
+
|
279
286
|
return workflow_id
|
280
287
|
|
281
288
|
def _execute_workflow_step(self, workflow_id: str, step_index: int) -> None:
|
@@ -283,37 +290,37 @@ class WorkflowRuntime:
|
|
283
290
|
if workflow_id not in self.active_workflows:
|
284
291
|
logger.error(f"❌ Workflow '{workflow_id}' not found")
|
285
292
|
return
|
286
|
-
|
293
|
+
|
287
294
|
workflow_state = self.active_workflows[workflow_id]
|
288
295
|
workflow_def = workflow_state["definition"]
|
289
296
|
steps = workflow_def.get("steps", [])
|
290
|
-
|
297
|
+
|
291
298
|
if step_index >= len(steps):
|
292
299
|
logger.info(f"🏁 Workflow '{workflow_id}' completed")
|
293
300
|
return
|
294
|
-
|
301
|
+
|
295
302
|
step = steps[step_index]
|
296
303
|
step_id = f"step_{step_index}"
|
297
|
-
|
304
|
+
|
298
305
|
# Extract step configuration
|
299
306
|
agent_id = step.get("agent")
|
300
307
|
task_name = step.get("task")
|
301
308
|
step_input = step.get("input", {})
|
302
|
-
|
309
|
+
|
303
310
|
# Resolve input data with context
|
304
311
|
resolved_input = self._resolve_input_data(step_input, workflow_state["context"])
|
305
|
-
|
312
|
+
|
306
313
|
logger.info(f"📋 Executing step {step_index}: {agent_id}.{task_name}")
|
307
|
-
|
314
|
+
|
308
315
|
# Create task
|
309
316
|
task_id = self.task_registry.create_task(
|
310
317
|
workflow_id=workflow_id,
|
311
318
|
step_id=step_id,
|
312
319
|
agent_id=agent_id,
|
313
320
|
task_name=task_name,
|
314
|
-
input_data=resolved_input
|
321
|
+
input_data=resolved_input,
|
315
322
|
)
|
316
|
-
|
323
|
+
|
317
324
|
# Execute task
|
318
325
|
self._execute_task(task_id, workflow_id, step_index)
|
319
326
|
|
@@ -323,88 +330,76 @@ class WorkflowRuntime:
|
|
323
330
|
if not task:
|
324
331
|
logger.error(f"❌ Task '{task_id}' not found")
|
325
332
|
return
|
326
|
-
|
333
|
+
|
327
334
|
# Get agent instance
|
328
335
|
agent = self.agent_registry.get_agent(task.agent_id)
|
329
336
|
if not agent:
|
330
337
|
self.task_registry.update_task_status(
|
331
|
-
task_id, TaskStatus.FAILED,
|
332
|
-
error=f"Agent '{task.agent_id}' not found"
|
338
|
+
task_id, TaskStatus.FAILED, error=f"Agent '{task.agent_id}' not found"
|
333
339
|
)
|
334
340
|
return
|
335
|
-
|
341
|
+
|
336
342
|
# Update task status
|
337
|
-
self.task_registry.update_task_status(
|
338
|
-
|
339
|
-
started_at=time.time()
|
340
|
-
)
|
341
|
-
|
343
|
+
self.task_registry.update_task_status(task_id, TaskStatus.RUNNING, started_at=time.time())
|
344
|
+
|
342
345
|
try:
|
343
346
|
# Prepare message for agent
|
344
|
-
message = {
|
345
|
-
|
346
|
-
**task.input_data
|
347
|
-
}
|
348
|
-
|
347
|
+
message = {"task": task.task_name, **task.input_data}
|
348
|
+
|
349
349
|
logger.info(f"📨 Sending task '{task.task_name}' to agent '{task.agent_id}'")
|
350
|
-
|
350
|
+
|
351
351
|
# Execute via orchestrator or direct call
|
352
352
|
if self.orchestrator:
|
353
353
|
result = self.orchestrator.send_message(task.agent_id, message)
|
354
354
|
else:
|
355
355
|
result = agent.handle_message(message)
|
356
|
-
|
356
|
+
|
357
357
|
# Check for errors
|
358
358
|
if isinstance(result, dict) and "error" in result:
|
359
359
|
self.task_registry.update_task_status(
|
360
|
-
task_id, TaskStatus.FAILED,
|
361
|
-
error=result["error"]
|
360
|
+
task_id, TaskStatus.FAILED, error=result["error"]
|
362
361
|
)
|
363
362
|
logger.error(f"❌ Task '{task_id}' failed: {result['error']}")
|
364
363
|
return
|
365
|
-
|
364
|
+
|
366
365
|
# Task completed successfully
|
367
|
-
self.task_registry.update_task_status(
|
368
|
-
|
369
|
-
output_data=result
|
370
|
-
)
|
371
|
-
|
366
|
+
self.task_registry.update_task_status(task_id, TaskStatus.COMPLETED, output_data=result)
|
367
|
+
|
372
368
|
logger.info(f"✅ Task '{task_id}' completed successfully")
|
373
|
-
|
369
|
+
|
374
370
|
# Continue workflow
|
375
371
|
self._handle_task_completion(task_id, workflow_id, step_index, result)
|
376
|
-
|
372
|
+
|
377
373
|
except Exception as e:
|
378
|
-
self.task_registry.update_task_status(
|
379
|
-
task_id, TaskStatus.FAILED,
|
380
|
-
error=str(e)
|
381
|
-
)
|
374
|
+
self.task_registry.update_task_status(task_id, TaskStatus.FAILED, error=str(e))
|
382
375
|
logger.error(f"❌ Task '{task_id}' failed with exception: {e}")
|
383
376
|
|
384
|
-
def _handle_task_completion(
|
377
|
+
def _handle_task_completion(
|
378
|
+
self, task_id: str, workflow_id: str, step_index: int, result: Dict[str, Any]
|
379
|
+
) -> None:
|
385
380
|
"""Handle task completion and route to next step."""
|
386
381
|
workflow_state = self.active_workflows[workflow_id]
|
387
382
|
workflow_def = workflow_state["definition"]
|
388
383
|
steps = workflow_def.get("steps", [])
|
389
|
-
|
384
|
+
|
390
385
|
if step_index >= len(steps):
|
391
386
|
return
|
392
|
-
|
387
|
+
|
393
388
|
current_step = steps[step_index]
|
394
|
-
|
389
|
+
|
395
390
|
# Convert result to dictionary if it's a Pydantic model
|
396
|
-
if hasattr(result,
|
391
|
+
if hasattr(result, "model_dump"):
|
397
392
|
result_dict = result.model_dump()
|
398
393
|
logger.debug(f"🔧 Converted Pydantic model to dict: {result_dict}")
|
399
|
-
elif hasattr(result,
|
394
|
+
elif hasattr(result, "dict"):
|
400
395
|
result_dict = result.dict()
|
401
396
|
logger.debug(f"🔧 Converted Pydantic model to dict (legacy): {result_dict}")
|
402
397
|
else:
|
403
398
|
result_dict = result
|
404
|
-
|
399
|
+
|
405
400
|
# Update workflow context with result
|
406
401
|
workflow_state["context"].update({"output": result_dict})
|
407
|
-
|
402
|
+
|
408
403
|
# Check for routing
|
409
404
|
route_config = current_step.get("route_output_to")
|
410
405
|
if route_config:
|
@@ -412,47 +407,90 @@ class WorkflowRuntime:
|
|
412
407
|
next_agent_id = route_config.get("agent")
|
413
408
|
next_task_name = route_config.get("task")
|
414
409
|
input_mapping = route_config.get("input_mapping", {})
|
415
|
-
|
410
|
+
|
416
411
|
logger.debug(f"🔍 Input mapping: {input_mapping}")
|
417
412
|
logger.debug(f"🔍 Available output data: {result_dict}")
|
418
|
-
|
413
|
+
|
419
414
|
# Resolve input mapping
|
420
|
-
next_input = self._resolve_input_mapping(
|
421
|
-
|
415
|
+
next_input = self._resolve_input_mapping(
|
416
|
+
input_mapping, result_dict, workflow_state["context"]
|
417
|
+
)
|
418
|
+
|
422
419
|
logger.info(f"🔄 Routing output to {next_agent_id}.{next_task_name}")
|
423
420
|
logger.debug(f"🔍 Resolved input for next task: {next_input}")
|
424
|
-
|
421
|
+
|
425
422
|
# Create and execute next task
|
426
423
|
next_task_id = self.task_registry.create_task(
|
427
424
|
workflow_id=workflow_id,
|
428
425
|
step_id=f"routed_step_{step_index}",
|
429
426
|
agent_id=next_agent_id,
|
430
427
|
task_name=next_task_name,
|
431
|
-
input_data=next_input
|
428
|
+
input_data=next_input,
|
432
429
|
)
|
433
|
-
|
430
|
+
|
434
431
|
self._execute_task(next_task_id, workflow_id, step_index + 1)
|
435
432
|
else:
|
436
433
|
# Continue to next step
|
437
434
|
self._execute_workflow_step(workflow_id, step_index + 1)
|
438
435
|
|
439
|
-
def _resolve_input_data(
|
436
|
+
def _resolve_input_data(
|
437
|
+
self, input_config: Dict[str, Any], context: Dict[str, Any]
|
438
|
+
) -> Dict[str, Any]:
|
440
439
|
"""Resolve input data with context variables."""
|
441
440
|
resolved = {}
|
442
441
|
for key, value in input_config.items():
|
443
442
|
if isinstance(value, str) and value.startswith("{{") and value.endswith("}}"):
|
444
443
|
# Template variable
|
445
|
-
|
446
|
-
|
444
|
+
template_content = value[2:-2].strip()
|
445
|
+
|
446
|
+
# Handle default values (e.g., "input.branch | default('main')")
|
447
|
+
if " | default(" in template_content:
|
448
|
+
var_path, default_part = template_content.split(" | default(", 1)
|
449
|
+
var_path = var_path.strip()
|
450
|
+
default_value = default_part.rstrip(")").strip("'\"")
|
451
|
+
|
452
|
+
result = self._resolve_template_path(context, var_path)
|
453
|
+
resolved[key] = result if result is not None else default_value
|
454
|
+
else:
|
455
|
+
# Simple template variable
|
456
|
+
resolved[key] = self._resolve_template_path(context, template_content)
|
457
|
+
elif isinstance(value, dict):
|
458
|
+
# Recursively resolve nested dictionaries
|
459
|
+
resolved[key] = self._resolve_input_data(value, context)
|
447
460
|
else:
|
448
461
|
resolved[key] = value
|
449
462
|
return resolved
|
450
463
|
|
451
|
-
def
|
464
|
+
def _resolve_template_path(self, context: Dict[str, Any], path: str) -> Any:
|
465
|
+
"""Resolve template path including steps.* references."""
|
466
|
+
if path.startswith("steps."):
|
467
|
+
# Handle steps.step_name.output.field syntax
|
468
|
+
parts = path.split(".")
|
469
|
+
if len(parts) >= 4 and parts[2] == "output":
|
470
|
+
step_name = parts[1]
|
471
|
+
field_path = ".".join(parts[3:])
|
472
|
+
|
473
|
+
# Look for step output in context
|
474
|
+
if "output" in context and isinstance(context["output"], dict):
|
475
|
+
return self._get_nested_value(context["output"], field_path)
|
476
|
+
return None
|
477
|
+
else:
|
478
|
+
return None
|
479
|
+
else:
|
480
|
+
# Regular context path
|
481
|
+
return self._get_nested_value(context, path)
|
482
|
+
|
483
|
+
def _resolve_input_mapping(
|
484
|
+
self, mapping: Dict[str, str], output: Dict[str, Any], context: Dict[str, Any]
|
485
|
+
) -> Dict[str, Any]:
|
452
486
|
"""Resolve input mapping with output and context."""
|
453
487
|
resolved = {}
|
454
488
|
for target_key, source_template in mapping.items():
|
455
|
-
if
|
489
|
+
if (
|
490
|
+
isinstance(source_template, str)
|
491
|
+
and source_template.startswith("{{")
|
492
|
+
and source_template.endswith("}}")
|
493
|
+
):
|
456
494
|
var_path = source_template[2:-2].strip()
|
457
495
|
if var_path.startswith("output."):
|
458
496
|
# From current output
|
@@ -467,7 +505,7 @@ class WorkflowRuntime:
|
|
467
505
|
|
468
506
|
def _get_nested_value(self, data: Dict[str, Any], path: str) -> Any:
|
469
507
|
"""Get nested value from dictionary using dot notation."""
|
470
|
-
keys = path.split(
|
508
|
+
keys = path.split(".")
|
471
509
|
current = data
|
472
510
|
for key in keys:
|
473
511
|
if isinstance(current, dict) and key in current:
|
@@ -480,17 +518,17 @@ class WorkflowRuntime:
|
|
480
518
|
"""Get workflow execution status."""
|
481
519
|
if workflow_id not in self.active_workflows:
|
482
520
|
return None
|
483
|
-
|
521
|
+
|
484
522
|
workflow_state = self.active_workflows[workflow_id]
|
485
523
|
tasks = self.task_registry.get_workflow_tasks(workflow_id)
|
486
|
-
|
524
|
+
|
487
525
|
return {
|
488
526
|
"workflow_id": workflow_id,
|
489
527
|
"name": workflow_state["name"],
|
490
528
|
"current_step": workflow_state["current_step"],
|
491
529
|
"started_at": workflow_state["started_at"],
|
492
530
|
"context": workflow_state["context"],
|
493
|
-
"tasks": [task.to_dict() for task in tasks]
|
531
|
+
"tasks": [task.to_dict() for task in tasks],
|
494
532
|
}
|
495
533
|
|
496
534
|
def get_runtime_status(self) -> Dict[str, Any]:
|
@@ -498,11 +536,11 @@ class WorkflowRuntime:
|
|
498
536
|
return {
|
499
537
|
"agents": {
|
500
538
|
"registered": len(self.agent_registry.agents),
|
501
|
-
"agents": [agent.to_dict() for agent in self.agent_registry.agents.values()]
|
539
|
+
"agents": [agent.to_dict() for agent in self.agent_registry.agents.values()],
|
502
540
|
},
|
503
541
|
"tasks": self.task_registry.get_task_summary(),
|
504
542
|
"workflows": {
|
505
543
|
"active": len(self.active_workflows),
|
506
|
-
"configured": len(self.workflow_config.get(
|
507
|
-
}
|
508
|
-
}
|
544
|
+
"configured": len(self.workflow_config.get("workflows", {})),
|
545
|
+
},
|
546
|
+
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: dacp
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.4
|
4
4
|
Summary: Declarative Agent Communication Protocol - A protocol for managing LLM/agent communications and tool function calls
|
5
5
|
Author-email: Andrew Whitehouse <andrew.whitehouse@example.com>
|
6
6
|
License: MIT
|
@@ -26,20 +26,25 @@ Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE
|
27
27
|
Requires-Dist: requests>=2.25.0
|
28
28
|
Requires-Dist: pyyaml>=5.4.0
|
29
|
+
Requires-Dist: pydantic>=2.0.0
|
29
30
|
Provides-Extra: openai
|
30
31
|
Requires-Dist: openai>=1.0.0; extra == "openai"
|
31
32
|
Provides-Extra: anthropic
|
32
33
|
Requires-Dist: anthropic>=0.18.0; extra == "anthropic"
|
33
34
|
Provides-Extra: local
|
34
35
|
Requires-Dist: requests>=2.25.0; extra == "local"
|
36
|
+
Provides-Extra: api
|
37
|
+
Requires-Dist: fastapi>=0.104.0; extra == "api"
|
38
|
+
Requires-Dist: uvicorn[standard]>=0.24.0; extra == "api"
|
35
39
|
Provides-Extra: all
|
36
40
|
Requires-Dist: openai>=1.0.0; extra == "all"
|
37
41
|
Requires-Dist: anthropic>=0.18.0; extra == "all"
|
42
|
+
Requires-Dist: fastapi>=0.104.0; extra == "all"
|
43
|
+
Requires-Dist: uvicorn[standard]>=0.24.0; extra == "all"
|
38
44
|
Provides-Extra: dev
|
39
45
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
40
46
|
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
41
|
-
Requires-Dist:
|
42
|
-
Requires-Dist: flake8>=4.0.0; extra == "dev"
|
47
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
43
48
|
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
44
49
|
Requires-Dist: types-requests>=2.25.0; extra == "dev"
|
45
50
|
Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
dacp/__init__.py,sha256=UjSEhLapHynmUbNCV6fRazgXVS7HYfPGdR30iJG3m44,2224
|
2
|
+
dacp/api.py,sha256=p771UaXbIzhkJMtPi-SKtbyFZAiWJy1tUES-iSvEFyU,11736
|
3
|
+
dacp/cli.py,sha256=VesLS41TmskfvijqNzn9QnS8urFrOlLN6txauNhe38w,9449
|
4
|
+
dacp/exceptions.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
dacp/intelligence.py,sha256=63dQDug_WvSuHxlsAR4lOMtf7UGmtU74j5wFRJnmv9c,9526
|
6
|
+
dacp/json_parser.py,sha256=QGeoXIYZfHQvDYmo1awCxfTLx7jJj7qpjsmDtXMxK1A,8076
|
7
|
+
dacp/llm.py,sha256=K78QefD3LCOBTrsNHtfRs-UzcHNYCJNxcJ28HGirwfU,1064
|
8
|
+
dacp/logging_config.py,sha256=Gfxfk_t8m8gyciS9stAUGYANrYmKQ9F_XjgOyUATuhY,3895
|
9
|
+
dacp/main.py,sha256=YReioZotkURiYMuMLVf_-hPzVPSpqA5Esgwz7D36DhE,229
|
10
|
+
dacp/orchestrator.py,sha256=k-yrnGiz-Rtts4HphIVIwhULIE-dvQNzBD_bhuQndZ0,9679
|
11
|
+
dacp/protocol.py,sha256=DVhLTdyDVlAu8ETSEX8trPeycKfMeirHwcWQ8-BY7eA,1026
|
12
|
+
dacp/tools.py,sha256=YXK4MzL3Aahsnj26NveDLdEDO1ZkPxrwZpD1JfALS10,2846
|
13
|
+
dacp/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
|
+
dacp/workflow.py,sha256=ikrJhci9119Xb9fe0R3LMscmY4rtTjy9QE9pbJYFh3w,14481
|
15
|
+
dacp/workflow_runtime.py,sha256=JijfgcYz3xnXP3GePciuWszG7SK3Dp7BSTeN0c5H86Y,19876
|
16
|
+
dacp-0.3.4.dist-info/licenses/LICENSE,sha256=tb5kgUYRypHqAy8wlrJUBSYI5l1SBmawSYHmCC-MVW0,1074
|
17
|
+
dacp-0.3.4.dist-info/METADATA,sha256=ojeVx0qWxHJQN_HuJC_ne2T02L9tH8JDUG01TwD4W9c,25970
|
18
|
+
dacp-0.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
19
|
+
dacp-0.3.4.dist-info/entry_points.txt,sha256=-4RWvAkDznguXlMyDO0ZReOkSplbuCYLXu5IX8RIiCg,39
|
20
|
+
dacp-0.3.4.dist-info/top_level.txt,sha256=Qxy0cy5jl7ttTQoGFlY9LXB6CbSvsekJ2y0P8I7L1zA,5
|
21
|
+
dacp-0.3.4.dist-info/RECORD,,
|
dacp-0.3.3.dist-info/RECORD
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
dacp/__init__.py,sha256=VnIaZHQutoNLVmtCRV1sMk3oAjf4HtF42kiXmuJ21Tw,2224
|
2
|
-
dacp/exceptions.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
dacp/intelligence.py,sha256=z8RqRYXKKKDd9MCm1KLBNQ3DJ9Zl4ZntbjFcaqtuv9s,9713
|
4
|
-
dacp/json_parser.py,sha256=qQ3zWlhaiyQUyDRUQPHaqkwAd29uM2zlGflsPKeamB4,8245
|
5
|
-
dacp/llm.py,sha256=K78QefD3LCOBTrsNHtfRs-UzcHNYCJNxcJ28HGirwfU,1064
|
6
|
-
dacp/logging_config.py,sha256=g5iMe9mloZag4oFQ9FQrRTikDTCI-XxeTGX0Y1KXVMw,3927
|
7
|
-
dacp/main.py,sha256=YReioZotkURiYMuMLVf_-hPzVPSpqA5Esgwz7D36DhE,229
|
8
|
-
dacp/orchestrator.py,sha256=fTOlWz95Xs1W1OxsRht3zyLyU5UnrLXBAFOfkqCB17k,9915
|
9
|
-
dacp/protocol.py,sha256=DVhLTdyDVlAu8ETSEX8trPeycKfMeirHwcWQ8-BY7eA,1026
|
10
|
-
dacp/tools.py,sha256=wfuUQ12UVvyMLUcDA4GGxwwzQJ-k4ftWbewg7qwNQGg,2872
|
11
|
-
dacp/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
-
dacp/workflow.py,sha256=AzuKGUiKnifEHsAO9b7p3OB4I-gb0tKWIco15clv-Wg,14322
|
13
|
-
dacp/workflow_runtime.py,sha256=X8PWlYvMUD36gGRGsKKKvVCEcJMGeKfzIg4JMB8iEMA,18596
|
14
|
-
dacp-0.3.3.dist-info/licenses/LICENSE,sha256=tb5kgUYRypHqAy8wlrJUBSYI5l1SBmawSYHmCC-MVW0,1074
|
15
|
-
dacp-0.3.3.dist-info/METADATA,sha256=4tu9_DW7z2iiB9MHMKEgFylPXx-NLgPGMprrpElBn6M,25756
|
16
|
-
dacp-0.3.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
17
|
-
dacp-0.3.3.dist-info/top_level.txt,sha256=Qxy0cy5jl7ttTQoGFlY9LXB6CbSvsekJ2y0P8I7L1zA,5
|
18
|
-
dacp-0.3.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|