dacp 0.3.2__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.
@@ -0,0 +1,546 @@
1
+ """
2
+ DACP Workflow Runtime - Declarative workflow execution from workflow.yaml
3
+
4
+ This module provides a runtime system that reads workflow.yaml files and
5
+ orchestrates agent collaboration through agent and task registries.
6
+ """
7
+
8
+ import logging
9
+ import time
10
+ import uuid
11
+ import yaml
12
+ import json
13
+ from typing import Dict, Any, List, Optional, Union
14
+ from pathlib import Path
15
+ from dataclasses import dataclass, field
16
+ from enum import Enum
17
+
18
+ logger = logging.getLogger("dacp.workflow_runtime")
19
+
20
+
21
+ class TaskStatus(Enum):
22
+ """Task execution status."""
23
+
24
+ PENDING = "pending"
25
+ RUNNING = "running"
26
+ COMPLETED = "completed"
27
+ FAILED = "failed"
28
+ CANCELLED = "cancelled"
29
+
30
+
31
+ @dataclass
32
+ class TaskExecution:
33
+ """Represents a task execution instance."""
34
+
35
+ id: str
36
+ workflow_id: str
37
+ step_id: str
38
+ agent_id: str
39
+ task_name: str
40
+ input_data: Dict[str, Any]
41
+ status: TaskStatus = TaskStatus.PENDING
42
+ output_data: Optional[Dict[str, Any]] = None
43
+ error: Optional[str] = None
44
+ created_at: float = field(default_factory=time.time)
45
+ started_at: Optional[float] = None
46
+ completed_at: Optional[float] = None
47
+ duration: Optional[float] = None
48
+
49
+ def to_dict(self) -> Dict[str, Any]:
50
+ """Convert to dictionary representation."""
51
+ return {
52
+ "id": self.id,
53
+ "workflow_id": self.workflow_id,
54
+ "step_id": self.step_id,
55
+ "agent_id": self.agent_id,
56
+ "task_name": self.task_name,
57
+ "input_data": self.input_data,
58
+ "status": self.status.value,
59
+ "output_data": self.output_data,
60
+ "error": self.error,
61
+ "created_at": self.created_at,
62
+ "started_at": self.started_at,
63
+ "completed_at": self.completed_at,
64
+ "duration": self.duration,
65
+ }
66
+
67
+
68
+ @dataclass
69
+ class RegisteredAgent:
70
+ """Represents a registered agent in the registry."""
71
+
72
+ id: str
73
+ agent_instance: Any
74
+ spec_file: Optional[str] = None
75
+ metadata: Dict[str, Any] = field(default_factory=dict)
76
+ registered_at: float = field(default_factory=time.time)
77
+ last_activity: Optional[float] = None
78
+
79
+ def to_dict(self) -> Dict[str, Any]:
80
+ """Convert to dictionary representation."""
81
+ return {
82
+ "id": self.id,
83
+ "agent_type": type(self.agent_instance).__name__,
84
+ "spec_file": self.spec_file,
85
+ "metadata": self.metadata,
86
+ "registered_at": self.registered_at,
87
+ "last_activity": self.last_activity,
88
+ }
89
+
90
+
91
+ class AgentRegistry:
92
+ """Registry for managing agent instances."""
93
+
94
+ def __init__(self) -> None:
95
+ self.agents: Dict[str, RegisteredAgent] = {}
96
+
97
+ def register_agent(
98
+ self,
99
+ agent_id: str,
100
+ agent_instance: Any,
101
+ spec_file: Optional[str] = None,
102
+ metadata: Optional[Dict[str, Any]] = None,
103
+ ) -> None:
104
+ """Register an agent instance."""
105
+ registered_agent = RegisteredAgent(
106
+ id=agent_id,
107
+ agent_instance=agent_instance,
108
+ spec_file=spec_file,
109
+ metadata=metadata or {},
110
+ )
111
+
112
+ self.agents[agent_id] = registered_agent
113
+ logger.info(f"🤖 Agent '{agent_id}' registered in registry")
114
+
115
+ def get_agent(self, agent_id: str) -> Optional[Any]:
116
+ """Get an agent instance by ID."""
117
+ if agent_id in self.agents:
118
+ self.agents[agent_id].last_activity = time.time()
119
+ return self.agents[agent_id].agent_instance
120
+ return None
121
+
122
+ def list_agents(self) -> List[str]:
123
+ """List all registered agent IDs."""
124
+ return list(self.agents.keys())
125
+
126
+ def get_agent_info(self, agent_id: str) -> Optional[Dict[str, Any]]:
127
+ """Get agent registration information."""
128
+ if agent_id in self.agents:
129
+ return self.agents[agent_id].to_dict()
130
+ return None
131
+
132
+ def unregister_agent(self, agent_id: str) -> bool:
133
+ """Unregister an agent."""
134
+ if agent_id in self.agents:
135
+ del self.agents[agent_id]
136
+ logger.info(f"🗑️ Agent '{agent_id}' unregistered from registry")
137
+ return True
138
+ return False
139
+
140
+
141
+ class TaskRegistry:
142
+ """Registry for managing task executions."""
143
+
144
+ def __init__(self) -> None:
145
+ self.tasks: Dict[str, TaskExecution] = {}
146
+ self.workflow_tasks: Dict[str, List[str]] = {} # workflow_id -> task_ids
147
+
148
+ def create_task(
149
+ self,
150
+ workflow_id: str,
151
+ step_id: str,
152
+ agent_id: str,
153
+ task_name: str,
154
+ input_data: Dict[str, Any],
155
+ ) -> str:
156
+ """Create a new task execution."""
157
+ task_id = str(uuid.uuid4())
158
+
159
+ task = TaskExecution(
160
+ id=task_id,
161
+ workflow_id=workflow_id,
162
+ step_id=step_id,
163
+ agent_id=agent_id,
164
+ task_name=task_name,
165
+ input_data=input_data,
166
+ )
167
+
168
+ self.tasks[task_id] = task
169
+
170
+ # Add to workflow tasks
171
+ if workflow_id not in self.workflow_tasks:
172
+ self.workflow_tasks[workflow_id] = []
173
+ self.workflow_tasks[workflow_id].append(task_id)
174
+
175
+ logger.info(
176
+ f"📋 Task '{task_id}' created for agent '{agent_id}' in workflow '{workflow_id}'"
177
+ )
178
+ return task_id
179
+
180
+ def get_task(self, task_id: str) -> Optional[TaskExecution]:
181
+ """Get a task by ID."""
182
+ return self.tasks.get(task_id)
183
+
184
+ def update_task_status(self, task_id: str, status: TaskStatus, **kwargs: Any) -> bool:
185
+ """Update task status and optional fields."""
186
+ if task_id not in self.tasks:
187
+ return False
188
+
189
+ task = self.tasks[task_id]
190
+ task.status = status
191
+
192
+ # Update optional fields
193
+ for key, value in kwargs.items():
194
+ if hasattr(task, key):
195
+ setattr(task, key, value)
196
+
197
+ # Calculate duration if completed
198
+ if status in [TaskStatus.COMPLETED, TaskStatus.FAILED] and task.started_at:
199
+ task.completed_at = time.time()
200
+ task.duration = task.completed_at - task.started_at
201
+
202
+ logger.info(f"📊 Task '{task_id}' status updated to {status.value}")
203
+ return True
204
+
205
+ def get_workflow_tasks(self, workflow_id: str) -> List[TaskExecution]:
206
+ """Get all tasks for a workflow."""
207
+ task_ids = self.workflow_tasks.get(workflow_id, [])
208
+ return [self.tasks[tid] for tid in task_ids if tid in self.tasks]
209
+
210
+ def get_task_summary(self) -> Dict[str, Any]:
211
+ """Get summary of all tasks."""
212
+ status_counts: Dict[str, int] = {}
213
+ for task in self.tasks.values():
214
+ status = task.status.value
215
+ status_counts[status] = status_counts.get(status, 0) + 1
216
+
217
+ return {
218
+ "total_tasks": len(self.tasks),
219
+ "status_counts": status_counts,
220
+ "workflows": len(self.workflow_tasks),
221
+ }
222
+
223
+
224
+ class WorkflowRuntime:
225
+ """DACP Workflow Runtime - Executes workflows from workflow.yaml"""
226
+
227
+ def __init__(self, orchestrator: Optional[Any] = None) -> None:
228
+ self.orchestrator = orchestrator
229
+ self.agent_registry = AgentRegistry()
230
+ self.task_registry = TaskRegistry()
231
+ self.workflow_config: Dict[str, Any] = {}
232
+ self.active_workflows: Dict[str, Dict[str, Any]] = {}
233
+
234
+ def load_workflow_config(self, config_path: str) -> None:
235
+ """Load workflow configuration from YAML file."""
236
+ config_file = Path(config_path)
237
+ if not config_file.exists():
238
+ raise FileNotFoundError(f"Workflow config file not found: {config_path}")
239
+
240
+ with open(config_file, "r") as f:
241
+ self.workflow_config = yaml.safe_load(f)
242
+
243
+ logger.info(f"📁 Loaded workflow config from {config_path}")
244
+ logger.info(f"📋 Found {len(self.workflow_config.get('workflows', {}))} workflows")
245
+
246
+ def register_agent_from_config(self, agent_id: str, agent_instance: Any) -> None:
247
+ """Register an agent instance based on workflow config."""
248
+ # Find agent spec in config
249
+ agent_spec = None
250
+ for agent_config in self.workflow_config.get("agents", []):
251
+ if agent_config["id"] == agent_id:
252
+ agent_spec = agent_config.get("spec")
253
+ break
254
+
255
+ self.agent_registry.register_agent(
256
+ agent_id=agent_id,
257
+ agent_instance=agent_instance,
258
+ spec_file=agent_spec,
259
+ metadata={"config_based": True},
260
+ )
261
+
262
+ def execute_workflow(
263
+ self, workflow_name: str, initial_input: Optional[Dict[str, Any]] = None
264
+ ) -> str:
265
+ """Execute a workflow by name."""
266
+ if workflow_name not in self.workflow_config.get("workflows", {}):
267
+ raise ValueError(f"Workflow '{workflow_name}' not found in config")
268
+
269
+ workflow_def = self.workflow_config["workflows"][workflow_name]
270
+ workflow_id = str(uuid.uuid4())
271
+
272
+ logger.info(f"🚀 Starting workflow '{workflow_name}' with ID '{workflow_id}'")
273
+
274
+ # Initialize workflow state
275
+ self.active_workflows[workflow_id] = {
276
+ "name": workflow_name,
277
+ "definition": workflow_def,
278
+ "current_step": 0,
279
+ "context": {"input": initial_input or {}},
280
+ "started_at": time.time(),
281
+ }
282
+
283
+ # Execute first step
284
+ self._execute_workflow_step(workflow_id, 0)
285
+
286
+ return workflow_id
287
+
288
+ def _execute_workflow_step(self, workflow_id: str, step_index: int) -> None:
289
+ """Execute a specific workflow step."""
290
+ if workflow_id not in self.active_workflows:
291
+ logger.error(f"❌ Workflow '{workflow_id}' not found")
292
+ return
293
+
294
+ workflow_state = self.active_workflows[workflow_id]
295
+ workflow_def = workflow_state["definition"]
296
+ steps = workflow_def.get("steps", [])
297
+
298
+ if step_index >= len(steps):
299
+ logger.info(f"🏁 Workflow '{workflow_id}' completed")
300
+ return
301
+
302
+ step = steps[step_index]
303
+ step_id = f"step_{step_index}"
304
+
305
+ # Extract step configuration
306
+ agent_id = step.get("agent")
307
+ task_name = step.get("task")
308
+ step_input = step.get("input", {})
309
+
310
+ # Resolve input data with context
311
+ resolved_input = self._resolve_input_data(step_input, workflow_state["context"])
312
+
313
+ logger.info(f"📋 Executing step {step_index}: {agent_id}.{task_name}")
314
+
315
+ # Create task
316
+ task_id = self.task_registry.create_task(
317
+ workflow_id=workflow_id,
318
+ step_id=step_id,
319
+ agent_id=agent_id,
320
+ task_name=task_name,
321
+ input_data=resolved_input,
322
+ )
323
+
324
+ # Execute task
325
+ self._execute_task(task_id, workflow_id, step_index)
326
+
327
+ def _execute_task(self, task_id: str, workflow_id: str, step_index: int) -> None:
328
+ """Execute a single task."""
329
+ task = self.task_registry.get_task(task_id)
330
+ if not task:
331
+ logger.error(f"❌ Task '{task_id}' not found")
332
+ return
333
+
334
+ # Get agent instance
335
+ agent = self.agent_registry.get_agent(task.agent_id)
336
+ if not agent:
337
+ self.task_registry.update_task_status(
338
+ task_id, TaskStatus.FAILED, error=f"Agent '{task.agent_id}' not found"
339
+ )
340
+ return
341
+
342
+ # Update task status
343
+ self.task_registry.update_task_status(task_id, TaskStatus.RUNNING, started_at=time.time())
344
+
345
+ try:
346
+ # Prepare message for agent
347
+ message = {"task": task.task_name, **task.input_data}
348
+
349
+ logger.info(f"📨 Sending task '{task.task_name}' to agent '{task.agent_id}'")
350
+
351
+ # Execute via orchestrator or direct call
352
+ if self.orchestrator:
353
+ result = self.orchestrator.send_message(task.agent_id, message)
354
+ else:
355
+ result = agent.handle_message(message)
356
+
357
+ # Check for errors
358
+ if isinstance(result, dict) and "error" in result:
359
+ self.task_registry.update_task_status(
360
+ task_id, TaskStatus.FAILED, error=result["error"]
361
+ )
362
+ logger.error(f"❌ Task '{task_id}' failed: {result['error']}")
363
+ return
364
+
365
+ # Task completed successfully
366
+ self.task_registry.update_task_status(task_id, TaskStatus.COMPLETED, output_data=result)
367
+
368
+ logger.info(f"✅ Task '{task_id}' completed successfully")
369
+
370
+ # Continue workflow
371
+ self._handle_task_completion(task_id, workflow_id, step_index, result)
372
+
373
+ except Exception as e:
374
+ self.task_registry.update_task_status(task_id, TaskStatus.FAILED, error=str(e))
375
+ logger.error(f"❌ Task '{task_id}' failed with exception: {e}")
376
+
377
+ def _handle_task_completion(
378
+ self, task_id: str, workflow_id: str, step_index: int, result: Dict[str, Any]
379
+ ) -> None:
380
+ """Handle task completion and route to next step."""
381
+ workflow_state = self.active_workflows[workflow_id]
382
+ workflow_def = workflow_state["definition"]
383
+ steps = workflow_def.get("steps", [])
384
+
385
+ if step_index >= len(steps):
386
+ return
387
+
388
+ current_step = steps[step_index]
389
+
390
+ # Convert result to dictionary if it's a Pydantic model
391
+ if hasattr(result, "model_dump"):
392
+ result_dict = result.model_dump()
393
+ logger.debug(f"🔧 Converted Pydantic model to dict: {result_dict}")
394
+ elif hasattr(result, "dict"):
395
+ result_dict = result.dict()
396
+ logger.debug(f"🔧 Converted Pydantic model to dict (legacy): {result_dict}")
397
+ else:
398
+ result_dict = result
399
+
400
+ # Update workflow context with result
401
+ workflow_state["context"].update({"output": result_dict})
402
+
403
+ # Check for routing
404
+ route_config = current_step.get("route_output_to")
405
+ if route_config:
406
+ # Route to next agent
407
+ next_agent_id = route_config.get("agent")
408
+ next_task_name = route_config.get("task")
409
+ input_mapping = route_config.get("input_mapping", {})
410
+
411
+ logger.debug(f"🔍 Input mapping: {input_mapping}")
412
+ logger.debug(f"🔍 Available output data: {result_dict}")
413
+
414
+ # Resolve input mapping
415
+ next_input = self._resolve_input_mapping(
416
+ input_mapping, result_dict, workflow_state["context"]
417
+ )
418
+
419
+ logger.info(f"🔄 Routing output to {next_agent_id}.{next_task_name}")
420
+ logger.debug(f"🔍 Resolved input for next task: {next_input}")
421
+
422
+ # Create and execute next task
423
+ next_task_id = self.task_registry.create_task(
424
+ workflow_id=workflow_id,
425
+ step_id=f"routed_step_{step_index}",
426
+ agent_id=next_agent_id,
427
+ task_name=next_task_name,
428
+ input_data=next_input,
429
+ )
430
+
431
+ self._execute_task(next_task_id, workflow_id, step_index + 1)
432
+ else:
433
+ # Continue to next step
434
+ self._execute_workflow_step(workflow_id, step_index + 1)
435
+
436
+ def _resolve_input_data(
437
+ self, input_config: Dict[str, Any], context: Dict[str, Any]
438
+ ) -> Dict[str, Any]:
439
+ """Resolve input data with context variables."""
440
+ resolved = {}
441
+ for key, value in input_config.items():
442
+ if isinstance(value, str) and value.startswith("{{") and value.endswith("}}"):
443
+ # Template variable
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)
460
+ else:
461
+ resolved[key] = value
462
+ return resolved
463
+
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]:
486
+ """Resolve input mapping with output and context."""
487
+ resolved = {}
488
+ for target_key, source_template in mapping.items():
489
+ if (
490
+ isinstance(source_template, str)
491
+ and source_template.startswith("{{")
492
+ and source_template.endswith("}}")
493
+ ):
494
+ var_path = source_template[2:-2].strip()
495
+ if var_path.startswith("output."):
496
+ # From current output
497
+ field_name = var_path[7:] # Remove "output."
498
+ resolved[target_key] = output.get(field_name, "")
499
+ else:
500
+ # From context
501
+ resolved[target_key] = self._get_nested_value(context, var_path)
502
+ else:
503
+ resolved[target_key] = source_template
504
+ return resolved
505
+
506
+ def _get_nested_value(self, data: Dict[str, Any], path: str) -> Any:
507
+ """Get nested value from dictionary using dot notation."""
508
+ keys = path.split(".")
509
+ current = data
510
+ for key in keys:
511
+ if isinstance(current, dict) and key in current:
512
+ current = current[key]
513
+ else:
514
+ return None
515
+ return current
516
+
517
+ def get_workflow_status(self, workflow_id: str) -> Optional[Dict[str, Any]]:
518
+ """Get workflow execution status."""
519
+ if workflow_id not in self.active_workflows:
520
+ return None
521
+
522
+ workflow_state = self.active_workflows[workflow_id]
523
+ tasks = self.task_registry.get_workflow_tasks(workflow_id)
524
+
525
+ return {
526
+ "workflow_id": workflow_id,
527
+ "name": workflow_state["name"],
528
+ "current_step": workflow_state["current_step"],
529
+ "started_at": workflow_state["started_at"],
530
+ "context": workflow_state["context"],
531
+ "tasks": [task.to_dict() for task in tasks],
532
+ }
533
+
534
+ def get_runtime_status(self) -> Dict[str, Any]:
535
+ """Get overall runtime status."""
536
+ return {
537
+ "agents": {
538
+ "registered": len(self.agent_registry.agents),
539
+ "agents": [agent.to_dict() for agent in self.agent_registry.agents.values()],
540
+ },
541
+ "tasks": self.task_registry.get_task_summary(),
542
+ "workflows": {
543
+ "active": len(self.active_workflows),
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.2
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: black>=22.0.0; extra == "dev"
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,,
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ dacp = dacp.cli:main
@@ -1,15 +0,0 @@
1
- dacp/__init__.py,sha256=5EUO_gnPX7DISwAuPPkDSWrHoH9MNEoDRjDG16c7q_w,1351
2
- dacp/exceptions.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- dacp/intelligence.py,sha256=z8RqRYXKKKDd9MCm1KLBNQ3DJ9Zl4ZntbjFcaqtuv9s,9713
4
- dacp/llm.py,sha256=K78QefD3LCOBTrsNHtfRs-UzcHNYCJNxcJ28HGirwfU,1064
5
- dacp/logging_config.py,sha256=g5iMe9mloZag4oFQ9FQrRTikDTCI-XxeTGX0Y1KXVMw,3927
6
- dacp/main.py,sha256=YReioZotkURiYMuMLVf_-hPzVPSpqA5Esgwz7D36DhE,229
7
- dacp/orchestrator.py,sha256=5GxAVQFYW6OkNB8O5TT2eaJtQat7YUN_je7j-V0kXNM,9315
8
- dacp/protocol.py,sha256=DVhLTdyDVlAu8ETSEX8trPeycKfMeirHwcWQ8-BY7eA,1026
9
- dacp/tools.py,sha256=wfuUQ12UVvyMLUcDA4GGxwwzQJ-k4ftWbewg7qwNQGg,2872
10
- dacp/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- dacp-0.3.2.dist-info/licenses/LICENSE,sha256=tb5kgUYRypHqAy8wlrJUBSYI5l1SBmawSYHmCC-MVW0,1074
12
- dacp-0.3.2.dist-info/METADATA,sha256=RHlO4D7HV5kNPendOYH9yd3c5hzDOsIKf8bMSJcaNEk,25756
13
- dacp-0.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
14
- dacp-0.3.2.dist-info/top_level.txt,sha256=Qxy0cy5jl7ttTQoGFlY9LXB6CbSvsekJ2y0P8I7L1zA,5
15
- dacp-0.3.2.dist-info/RECORD,,
File without changes