dacp 0.3.0__py3-none-any.whl → 0.3.1__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 CHANGED
@@ -17,22 +17,43 @@ from .tools import (
17
17
  from .llm import call_llm
18
18
  from .intelligence import invoke_intelligence
19
19
  from .orchestrator import Orchestrator, Agent
20
+ from .logging_config import (
21
+ setup_dacp_logging,
22
+ enable_debug_logging,
23
+ enable_info_logging,
24
+ enable_quiet_logging,
25
+ set_dacp_log_level,
26
+ disable_dacp_logging,
27
+ enable_dacp_logging,
28
+ )
20
29
 
21
30
  __version__ = "0.3.0"
22
31
 
23
32
  __all__ = [
33
+ # Protocol functions
24
34
  "parse_agent_response",
25
- "is_tool_request",
35
+ "is_tool_request",
26
36
  "get_tool_request",
27
37
  "wrap_tool_result",
28
38
  "is_final_response",
29
39
  "get_final_response",
40
+ # Tool functions
30
41
  "register_tool",
31
42
  "run_tool",
32
43
  "TOOL_REGISTRY",
33
44
  "file_writer",
45
+ # LLM functions
34
46
  "call_llm",
35
47
  "invoke_intelligence",
48
+ # Agent orchestration
36
49
  "Orchestrator",
37
50
  "Agent",
51
+ # Logging configuration
52
+ "setup_dacp_logging",
53
+ "enable_debug_logging",
54
+ "enable_info_logging",
55
+ "enable_quiet_logging",
56
+ "set_dacp_log_level",
57
+ "disable_dacp_logging",
58
+ "enable_dacp_logging",
38
59
  ]
dacp/intelligence.py CHANGED
@@ -6,7 +6,8 @@ import os
6
6
  import logging
7
7
  from typing import Dict, Any, Optional
8
8
 
9
- log = logging.getLogger(__name__)
9
+ # Set up logger for this module
10
+ logger = logging.getLogger("dacp.intelligence")
10
11
 
11
12
 
12
13
  class IntelligenceError(Exception):
@@ -42,27 +43,58 @@ def invoke_intelligence(prompt: str, config: Dict[str, Any]) -> str:
42
43
  """
43
44
  engine = config.get("engine")
44
45
  if not engine:
46
+ logger.error("❌ Missing 'engine' in intelligence configuration")
45
47
  raise ConfigurationError("Missing 'engine' in intelligence configuration")
46
48
 
47
49
  engine = engine.lower()
50
+ model = config.get("model", "default")
48
51
 
49
- if engine == "openai":
50
- return _invoke_openai(prompt, config)
51
- elif engine == "anthropic":
52
- return _invoke_anthropic(prompt, config)
53
- elif engine == "azure":
54
- return _invoke_azure_openai(prompt, config)
55
- elif engine == "local":
56
- return _invoke_local(prompt, config)
57
- else:
58
- raise UnsupportedProviderError(f"Unsupported intelligence engine: {engine}")
52
+ logger.info(f"🧠 Invoking intelligence: engine='{engine}', model='{model}'")
53
+ logger.debug(f"📋 Prompt length: {len(prompt)} characters")
54
+ logger.debug(f"⚙️ Full config: {_sanitize_config_for_logging(config)}")
55
+
56
+ import time
57
+ start_time = time.time()
58
+
59
+ try:
60
+ if engine == "openai":
61
+ result = _invoke_openai(prompt, config)
62
+ elif engine == "anthropic":
63
+ result = _invoke_anthropic(prompt, config)
64
+ elif engine == "azure":
65
+ result = _invoke_azure_openai(prompt, config)
66
+ elif engine == "local":
67
+ result = _invoke_local(prompt, config)
68
+ else:
69
+ logger.error(f"❌ Unsupported intelligence engine: {engine}")
70
+ raise UnsupportedProviderError(f"Unsupported intelligence engine: {engine}")
71
+
72
+ execution_time = time.time() - start_time
73
+ logger.info(f"✅ Intelligence response received in {execution_time:.3f}s (length: {len(result)} chars)")
74
+ logger.debug(f"📤 Response preview: {result[:100]}{'...' if len(result) > 100 else ''}")
75
+
76
+ return result
77
+
78
+ except (IntelligenceError, UnsupportedProviderError, ConfigurationError):
79
+ # Re-raise our own exceptions without modification
80
+ execution_time = time.time() - start_time
81
+ logger.error(f"❌ Intelligence call failed after {execution_time:.3f}s")
82
+ raise
83
+ except Exception as e:
84
+ execution_time = time.time() - start_time
85
+ logger.error(f"❌ Unexpected intelligence error after {execution_time:.3f}s: {type(e).__name__}: {e}")
86
+ raise IntelligenceError(f"Unexpected error: {e}")
59
87
 
60
88
 
61
89
  def _invoke_openai(prompt: str, config: Dict[str, Any]) -> str:
62
90
  """Invoke OpenAI provider."""
91
+ logger.debug("🔵 Initializing OpenAI provider")
92
+
63
93
  try:
64
94
  import openai
95
+ logger.debug("✅ OpenAI package imported successfully")
65
96
  except ImportError:
97
+ logger.error("❌ OpenAI package not installed")
66
98
  raise IntelligenceError("OpenAI package not installed. Run: pip install openai")
67
99
 
68
100
  model = config.get("model", "gpt-4")
@@ -71,11 +103,17 @@ def _invoke_openai(prompt: str, config: Dict[str, Any]) -> str:
71
103
  temperature = config.get("temperature", 0.7)
72
104
  max_tokens = config.get("max_tokens", 150)
73
105
 
106
+ logger.debug(f"🔧 OpenAI config: model={model}, base_url={base_url}, temp={temperature}, max_tokens={max_tokens}")
107
+
74
108
  if not api_key:
109
+ logger.error("❌ OpenAI API key not found")
75
110
  raise ConfigurationError("OpenAI API key not found in config or OPENAI_API_KEY environment variable")
76
111
 
77
112
  try:
113
+ logger.debug("🔗 Creating OpenAI client")
78
114
  client = openai.OpenAI(api_key=api_key, base_url=base_url)
115
+
116
+ logger.debug("📡 Sending request to OpenAI API")
79
117
  response = client.chat.completions.create(
80
118
  model=model,
81
119
  messages=[{"role": "user", "content": prompt}],
@@ -85,19 +123,26 @@ def _invoke_openai(prompt: str, config: Dict[str, Any]) -> str:
85
123
 
86
124
  content = response.choices[0].message.content
87
125
  if content is None:
126
+ logger.error("❌ OpenAI returned empty response")
88
127
  raise IntelligenceError("OpenAI returned empty response")
128
+
129
+ logger.debug(f"✅ OpenAI API call successful")
89
130
  return content
90
131
 
91
132
  except Exception as e:
92
- log.error(f"OpenAI API error: {e}")
133
+ logger.error(f"OpenAI API error: {type(e).__name__}: {e}")
93
134
  raise IntelligenceError(f"OpenAI API error: {e}")
94
135
 
95
136
 
96
137
  def _invoke_anthropic(prompt: str, config: Dict[str, Any]) -> str:
97
138
  """Invoke Anthropic (Claude) provider."""
139
+ logger.debug("🟣 Initializing Anthropic provider")
140
+
98
141
  try:
99
142
  import anthropic
143
+ logger.debug("✅ Anthropic package imported successfully")
100
144
  except ImportError:
145
+ logger.error("❌ Anthropic package not installed")
101
146
  raise IntelligenceError("Anthropic package not installed. Run: pip install anthropic")
102
147
 
103
148
  model = config.get("model", "claude-3-haiku-20240307")
@@ -106,11 +151,17 @@ def _invoke_anthropic(prompt: str, config: Dict[str, Any]) -> str:
106
151
  max_tokens = config.get("max_tokens", 150)
107
152
  temperature = config.get("temperature", 0.7)
108
153
 
154
+ logger.debug(f"🔧 Anthropic config: model={model}, base_url={base_url}, temp={temperature}, max_tokens={max_tokens}")
155
+
109
156
  if not api_key:
157
+ logger.error("❌ Anthropic API key not found")
110
158
  raise ConfigurationError("Anthropic API key not found in config or ANTHROPIC_API_KEY environment variable")
111
159
 
112
160
  try:
161
+ logger.debug("🔗 Creating Anthropic client")
113
162
  client = anthropic.Anthropic(api_key=api_key, base_url=base_url)
163
+
164
+ logger.debug("📡 Sending request to Anthropic API")
114
165
  response = client.messages.create(
115
166
  model=model,
116
167
  max_tokens=max_tokens,
@@ -119,21 +170,28 @@ def _invoke_anthropic(prompt: str, config: Dict[str, Any]) -> str:
119
170
  )
120
171
 
121
172
  if not response.content or len(response.content) == 0:
173
+ logger.error("❌ Anthropic returned empty response")
122
174
  raise IntelligenceError("Anthropic returned empty response")
123
175
 
124
176
  # Anthropic returns a list of content blocks
125
- return response.content[0].text
177
+ result = response.content[0].text
178
+ logger.debug(f"✅ Anthropic API call successful")
179
+ return result
126
180
 
127
181
  except Exception as e:
128
- log.error(f"Anthropic API error: {e}")
182
+ logger.error(f"Anthropic API error: {type(e).__name__}: {e}")
129
183
  raise IntelligenceError(f"Anthropic API error: {e}")
130
184
 
131
185
 
132
186
  def _invoke_azure_openai(prompt: str, config: Dict[str, Any]) -> str:
133
187
  """Invoke Azure OpenAI provider."""
188
+ logger.debug("🔷 Initializing Azure OpenAI provider")
189
+
134
190
  try:
135
191
  import openai
192
+ logger.debug("✅ OpenAI package imported successfully")
136
193
  except ImportError:
194
+ logger.error("❌ OpenAI package not installed")
137
195
  raise IntelligenceError("OpenAI package not installed. Run: pip install openai")
138
196
 
139
197
  model = config.get("model", "gpt-4")
@@ -143,19 +201,25 @@ def _invoke_azure_openai(prompt: str, config: Dict[str, Any]) -> str:
143
201
  temperature = config.get("temperature", 0.7)
144
202
  max_tokens = config.get("max_tokens", 150)
145
203
 
204
+ logger.debug(f"🔧 Azure config: model={model}, endpoint={endpoint}, api_version={api_version}, temp={temperature}, max_tokens={max_tokens}")
205
+
146
206
  if not api_key:
207
+ logger.error("❌ Azure OpenAI API key not found")
147
208
  raise ConfigurationError("Azure OpenAI API key not found in config or AZURE_OPENAI_API_KEY environment variable")
148
209
 
149
210
  if not endpoint:
211
+ logger.error("❌ Azure OpenAI endpoint not found")
150
212
  raise ConfigurationError("Azure OpenAI endpoint not found in config or AZURE_OPENAI_ENDPOINT environment variable")
151
213
 
152
214
  try:
215
+ logger.debug("🔗 Creating Azure OpenAI client")
153
216
  client = openai.AzureOpenAI(
154
217
  api_key=api_key,
155
218
  azure_endpoint=endpoint,
156
219
  api_version=api_version
157
220
  )
158
221
 
222
+ logger.debug("📡 Sending request to Azure OpenAI API")
159
223
  response = client.chat.completions.create(
160
224
  model=model,
161
225
  messages=[{"role": "user", "content": prompt}],
@@ -165,11 +229,14 @@ def _invoke_azure_openai(prompt: str, config: Dict[str, Any]) -> str:
165
229
 
166
230
  content = response.choices[0].message.content
167
231
  if content is None:
232
+ logger.error("❌ Azure OpenAI returned empty response")
168
233
  raise IntelligenceError("Azure OpenAI returned empty response")
234
+
235
+ logger.debug(f"✅ Azure OpenAI API call successful")
169
236
  return content
170
237
 
171
238
  except Exception as e:
172
- log.error(f"Azure OpenAI API error: {e}")
239
+ logger.error(f"Azure OpenAI API error: {type(e).__name__}: {e}")
173
240
  raise IntelligenceError(f"Azure OpenAI API error: {e}")
174
241
 
175
242
 
@@ -182,9 +249,13 @@ def _invoke_local(prompt: str, config: Dict[str, Any]) -> str:
182
249
  temperature = config.get("temperature", 0.7)
183
250
  max_tokens = config.get("max_tokens", 150)
184
251
 
252
+ logger.debug(f"🟢 Initializing local provider")
253
+ logger.debug(f"🔧 Local config: model={model}, endpoint={endpoint}, temp={temperature}, max_tokens={max_tokens}")
254
+
185
255
  try:
186
256
  # Format for Ollama API
187
257
  if "ollama" in endpoint or ":11434" in endpoint:
258
+ logger.debug("📦 Using Ollama API format")
188
259
  payload = {
189
260
  "model": model,
190
261
  "prompt": prompt,
@@ -195,7 +266,7 @@ def _invoke_local(prompt: str, config: Dict[str, Any]) -> str:
195
266
  }
196
267
  }
197
268
  else:
198
- # Generic local API format
269
+ logger.debug("📦 Using generic local API format")
199
270
  payload = {
200
271
  "model": model,
201
272
  "prompt": prompt,
@@ -203,6 +274,7 @@ def _invoke_local(prompt: str, config: Dict[str, Any]) -> str:
203
274
  "max_tokens": max_tokens
204
275
  }
205
276
 
277
+ logger.debug(f"📡 Sending request to local endpoint: {endpoint}")
206
278
  response = requests.post(endpoint, json=payload, timeout=30)
207
279
  response.raise_for_status()
208
280
 
@@ -210,19 +282,25 @@ def _invoke_local(prompt: str, config: Dict[str, Any]) -> str:
210
282
 
211
283
  # Handle different response formats
212
284
  if "response" in result:
213
- return result["response"] # Ollama format
285
+ response_text = result["response"] # Ollama format
286
+ logger.debug("✅ Local API call successful (Ollama format)")
214
287
  elif "text" in result:
215
- return result["text"] # Generic format
288
+ response_text = result["text"] # Generic format
289
+ logger.debug("✅ Local API call successful (generic format)")
216
290
  elif "choices" in result and len(result["choices"]) > 0:
217
- return result["choices"][0].get("text", "") # OpenAI-compatible format
291
+ response_text = result["choices"][0].get("text", "") # OpenAI-compatible format
292
+ logger.debug("✅ Local API call successful (OpenAI-compatible format)")
218
293
  else:
294
+ logger.error(f"❌ Unexpected response format from local provider: {result}")
219
295
  raise IntelligenceError(f"Unexpected response format from local provider: {result}")
296
+
297
+ return response_text
220
298
 
221
299
  except requests.RequestException as e:
222
- log.error(f"Local provider request error: {e}")
300
+ logger.error(f"Local provider request error: {type(e).__name__}: {e}")
223
301
  raise IntelligenceError(f"Local provider request error: {e}")
224
302
  except Exception as e:
225
- log.error(f"Local provider error: {e}")
303
+ logger.error(f"Local provider error: {type(e).__name__}: {e}")
226
304
  raise IntelligenceError(f"Local provider error: {e}")
227
305
 
228
306
 
@@ -244,29 +322,57 @@ def validate_config(config: Dict[str, Any]) -> bool:
244
322
  Raises:
245
323
  ConfigurationError: If configuration is invalid
246
324
  """
325
+ logger.debug(f"🔍 Validating intelligence configuration")
326
+
247
327
  if not isinstance(config, dict):
328
+ logger.error("❌ Configuration must be a dictionary")
248
329
  raise ConfigurationError("Configuration must be a dictionary")
249
330
 
250
331
  engine = config.get("engine")
251
332
  if not engine:
333
+ logger.error("❌ Missing 'engine' in configuration")
252
334
  raise ConfigurationError("Missing 'engine' in configuration")
253
335
 
254
336
  if engine.lower() not in get_supported_engines():
337
+ logger.error(f"❌ Unsupported engine: {engine}")
255
338
  raise ConfigurationError(f"Unsupported engine: {engine}. Supported engines: {get_supported_engines()}")
256
339
 
257
340
  # Engine-specific validation
258
341
  engine = engine.lower()
342
+ logger.debug(f"🔧 Validating {engine} specific configuration")
259
343
 
260
344
  if engine in ["openai", "azure"]:
261
345
  if not config.get("api_key") and not os.getenv("OPENAI_API_KEY") and not os.getenv("AZURE_OPENAI_API_KEY"):
346
+ logger.error(f"❌ API key required for {engine} engine")
262
347
  raise ConfigurationError(f"API key required for {engine} engine")
263
348
 
264
349
  elif engine == "anthropic":
265
350
  if not config.get("api_key") and not os.getenv("ANTHROPIC_API_KEY"):
351
+ logger.error("❌ API key required for Anthropic engine")
266
352
  raise ConfigurationError("API key required for Anthropic engine")
267
353
 
268
354
  elif engine == "local":
269
355
  if not config.get("endpoint"):
270
356
  config["endpoint"] = "http://localhost:11434/api/generate" # Default to Ollama
357
+ logger.debug("🔧 Set default endpoint for local engine")
358
+
359
+ logger.debug(f"✅ Configuration validation successful for {engine}")
360
+ return True
361
+
362
+
363
+ def _sanitize_config_for_logging(config: Dict[str, Any]) -> Dict[str, Any]:
364
+ """Sanitize config for logging by masking sensitive data."""
365
+ sanitized = config.copy()
366
+
367
+ # Mask sensitive fields
368
+ sensitive_fields = ['api_key', 'password', 'token', 'secret']
369
+ for field in sensitive_fields:
370
+ if field in sanitized and sanitized[field]:
371
+ # Show first 4 and last 4 characters, mask the rest
372
+ value = str(sanitized[field])
373
+ if len(value) > 8:
374
+ sanitized[field] = f"{value[:4]}...{value[-4:]}"
375
+ else:
376
+ sanitized[field] = "***"
271
377
 
272
- return True
378
+ return sanitized
dacp/logging_config.py ADDED
@@ -0,0 +1,128 @@
1
+ """
2
+ DACP Logging Configuration
3
+
4
+ Utilities for configuring logging for DACP components.
5
+ """
6
+
7
+ import logging
8
+ import sys
9
+ from typing import Optional
10
+
11
+
12
+ def setup_dacp_logging(
13
+ level: str = "INFO",
14
+ format_style: str = "detailed",
15
+ include_timestamp: bool = True,
16
+ log_file: Optional[str] = None
17
+ ) -> None:
18
+ """
19
+ Set up logging for DACP components.
20
+
21
+ Args:
22
+ level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
23
+ format_style: Log format style ('simple', 'detailed', 'emoji')
24
+ include_timestamp: Whether to include timestamps in logs
25
+ log_file: Optional file path to also log to a file
26
+ """
27
+ # Define format styles
28
+ if format_style == "simple":
29
+ if include_timestamp:
30
+ log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
31
+ else:
32
+ log_format = "%(name)s - %(levelname)s - %(message)s"
33
+ elif format_style == "detailed":
34
+ if include_timestamp:
35
+ log_format = "%(asctime)s - %(name)s:%(lineno)d - %(levelname)s - %(message)s"
36
+ else:
37
+ log_format = "%(name)s:%(lineno)d - %(levelname)s - %(message)s"
38
+ elif format_style == "emoji":
39
+ # Emoji format doesn't include logger name since emojis provide context
40
+ if include_timestamp:
41
+ log_format = "%(asctime)s - %(message)s"
42
+ else:
43
+ log_format = "%(message)s"
44
+ else:
45
+ raise ValueError(f"Unknown format_style: {format_style}")
46
+
47
+ # Configure root logger for DACP components
48
+ logger = logging.getLogger("dacp")
49
+ logger.setLevel(getattr(logging, level.upper()))
50
+
51
+ # Remove existing handlers to avoid duplicates
52
+ for handler in logger.handlers[:]:
53
+ logger.removeHandler(handler)
54
+
55
+ # Create formatter
56
+ formatter = logging.Formatter(
57
+ log_format,
58
+ datefmt="%Y-%m-%d %H:%M:%S" if include_timestamp else None
59
+ )
60
+
61
+ # Console handler
62
+ console_handler = logging.StreamHandler(sys.stdout)
63
+ console_handler.setFormatter(formatter)
64
+ logger.addHandler(console_handler)
65
+
66
+ # Optional file handler
67
+ if log_file:
68
+ file_handler = logging.FileHandler(log_file)
69
+ file_handler.setFormatter(formatter)
70
+ logger.addHandler(file_handler)
71
+
72
+ # Prevent propagation to root logger to avoid duplicate messages
73
+ logger.propagate = False
74
+
75
+ logger.info(f"🚀 DACP logging configured: level={level}, style={format_style}")
76
+
77
+
78
+ def set_dacp_log_level(level: str) -> None:
79
+ """
80
+ Set the log level for all DACP components.
81
+
82
+ Args:
83
+ level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
84
+ """
85
+ logger = logging.getLogger("dacp")
86
+ logger.setLevel(getattr(logging, level.upper()))
87
+ logger.info(f"📊 DACP log level changed to {level}")
88
+
89
+
90
+ def disable_dacp_logging() -> None:
91
+ """Disable all DACP logging."""
92
+ logger = logging.getLogger("dacp")
93
+ logger.disabled = True
94
+
95
+
96
+ def enable_dacp_logging() -> None:
97
+ """Re-enable DACP logging."""
98
+ logger = logging.getLogger("dacp")
99
+ logger.disabled = False
100
+
101
+
102
+ def get_dacp_logger(name: str) -> logging.Logger:
103
+ """
104
+ Get a logger for a DACP component.
105
+
106
+ Args:
107
+ name: Logger name (usually __name__)
108
+
109
+ Returns:
110
+ Configured logger
111
+ """
112
+ return logging.getLogger(f"dacp.{name}")
113
+
114
+
115
+ # Convenience functions for quick setup
116
+ def enable_debug_logging(log_file: Optional[str] = None) -> None:
117
+ """Enable debug logging with detailed format."""
118
+ setup_dacp_logging(level="DEBUG", format_style="detailed", log_file=log_file)
119
+
120
+
121
+ def enable_info_logging(log_file: Optional[str] = None) -> None:
122
+ """Enable info logging with emoji format."""
123
+ setup_dacp_logging(level="INFO", format_style="emoji", log_file=log_file)
124
+
125
+
126
+ def enable_quiet_logging() -> None:
127
+ """Enable only error and critical logging."""
128
+ setup_dacp_logging(level="ERROR", format_style="simple", include_timestamp=False)
dacp/orchestrator.py CHANGED
@@ -3,9 +3,9 @@ DACP Orchestrator - Manages agent registration and message routing.
3
3
  """
4
4
 
5
5
  import logging
6
- from typing import Dict, Any, Optional, List, Callable
7
- import uuid
8
- import json
6
+ import time
7
+ from typing import Dict, Any, List, Optional
8
+ from .tools import run_tool, TOOL_REGISTRY
9
9
  from .protocol import (
10
10
  parse_agent_response,
11
11
  is_tool_request,
@@ -14,30 +14,31 @@ from .protocol import (
14
14
  is_final_response,
15
15
  get_final_response,
16
16
  )
17
- from .tools import run_tool
18
17
 
19
- log = logging.getLogger(__name__)
18
+ # Set up logger for this module
19
+ logger = logging.getLogger("dacp.orchestrator")
20
20
 
21
21
 
22
22
  class Agent:
23
- """Base agent interface that all agents should implement."""
23
+ """Base class for DACP agents."""
24
24
 
25
25
  def handle_message(self, message: Dict[str, Any]) -> Dict[str, Any]:
26
- """Handle incoming messages from the orchestrator."""
26
+ """Handle an incoming message. Subclasses should override this method."""
27
27
  raise NotImplementedError("Agents must implement handle_message method")
28
28
 
29
29
 
30
30
  class Orchestrator:
31
31
  """
32
32
  Central orchestrator for managing agents and routing messages.
33
- Handles agent registration, message routing, and tool execution.
34
33
  """
35
34
 
36
35
  def __init__(self):
36
+ """Initialize the orchestrator."""
37
37
  self.agents: Dict[str, Any] = {}
38
38
  self.conversation_history: List[Dict[str, Any]] = []
39
- self.session_id = str(uuid.uuid4())
40
-
39
+ self.session_id = f"session_{int(time.time())}"
40
+ logger.info(f"🎭 Orchestrator initialized with session ID: {self.session_id}")
41
+
41
42
  def register_agent(self, agent_id: str, agent: Any) -> None:
42
43
  """
43
44
  Register an agent with the orchestrator.
@@ -47,183 +48,145 @@ class Orchestrator:
47
48
  agent: Agent instance that implements handle_message method
48
49
  """
49
50
  if not hasattr(agent, 'handle_message'):
50
- raise ValueError(f"Agent {agent_id} must implement handle_message method")
51
+ logger.error(f"Agent '{agent_id}' does not implement handle_message method")
52
+ raise ValueError(f"Agent must implement handle_message method")
51
53
 
52
54
  self.agents[agent_id] = agent
53
- log.info(f"Registered agent: {agent_id}")
54
-
55
+ logger.info(f" Agent '{agent_id}' registered successfully (type: {type(agent).__name__})")
56
+ logger.debug(f"📊 Total registered agents: {len(self.agents)}")
57
+
55
58
  def unregister_agent(self, agent_id: str) -> bool:
56
59
  """
57
60
  Unregister an agent from the orchestrator.
58
61
 
59
62
  Args:
60
- agent_id: ID of the agent to unregister
63
+ agent_id: Unique identifier for the agent
61
64
 
62
65
  Returns:
63
- True if agent was found and removed, False otherwise
66
+ True if agent was successfully unregistered, False if not found
64
67
  """
65
68
  if agent_id in self.agents:
69
+ agent_type = type(self.agents[agent_id]).__name__
66
70
  del self.agents[agent_id]
67
- log.info(f"Unregistered agent: {agent_id}")
71
+ logger.info(f"🗑️ Agent '{agent_id}' unregistered successfully (was type: {agent_type})")
72
+ logger.debug(f"📊 Remaining registered agents: {len(self.agents)}")
68
73
  return True
69
- return False
70
-
71
- def get_agent(self, agent_id: str) -> Optional[Any]:
72
- """Get an agent by ID."""
73
- return self.agents.get(agent_id)
74
-
75
- def list_agents(self) -> List[str]:
76
- """Get list of registered agent IDs."""
77
- return list(self.agents.keys())
78
-
74
+ else:
75
+ logger.warning(f"⚠️ Attempted to unregister unknown agent: '{agent_id}'")
76
+ return False
77
+
79
78
  def send_message(self, agent_id: str, message: Dict[str, Any]) -> Dict[str, Any]:
80
79
  """
81
80
  Send a message to a specific agent.
82
81
 
83
82
  Args:
84
- agent_id: ID of the target agent
83
+ agent_id: Target agent identifier
85
84
  message: Message to send
86
85
 
87
86
  Returns:
88
- Response from the agent
89
-
90
- Raises:
91
- ValueError: If agent_id is not found
87
+ Response from the agent (or error if agent not found)
92
88
  """
89
+ logger.info(f"📨 Sending message to agent '{agent_id}'")
90
+ logger.debug(f"📋 Message content: {message}")
91
+
93
92
  if agent_id not in self.agents:
94
- raise ValueError(f"Agent {agent_id} not found")
95
-
96
- agent = self.agents[agent_id]
93
+ error_msg = f"Agent '{agent_id}' not found"
94
+ logger.error(f"❌ {error_msg}")
95
+ logger.debug(f"📊 Available agents: {list(self.agents.keys())}")
96
+ return {"error": error_msg}
97
97
 
98
- # Add metadata to message
99
- enriched_message = {
100
- "session_id": self.session_id,
101
- "timestamp": self._get_timestamp(),
102
- **message
103
- }
98
+ agent = self.agents[agent_id]
104
99
 
105
100
  try:
106
- # Send message to agent
107
- response = agent.handle_message(enriched_message)
101
+ start_time = time.time()
102
+ logger.debug(f"🔄 Calling handle_message on agent '{agent_id}'")
108
103
 
109
- # Log the interaction
110
- self.conversation_history.append({
111
- "type": "message",
112
- "agent_id": agent_id,
113
- "message": enriched_message,
114
- "response": response,
115
- "timestamp": self._get_timestamp()
116
- })
104
+ response = agent.handle_message(message)
117
105
 
106
+ processing_time = time.time() - start_time
107
+ logger.info(f"✅ Agent '{agent_id}' responded in {processing_time:.3f}s")
108
+ logger.debug(f"📤 Agent response: {response}")
109
+
110
+ # Check if agent requested a tool
111
+ if is_tool_request(response):
112
+ logger.info(f"🔧 Agent '{agent_id}' requested tool execution")
113
+ tool_name, tool_args = get_tool_request(response)
114
+ logger.info(f"🛠️ Executing tool: '{tool_name}' with args: {tool_args}")
115
+
116
+ if tool_name in TOOL_REGISTRY:
117
+ try:
118
+ tool_start_time = time.time()
119
+ tool_result = run_tool(tool_name, tool_args)
120
+ tool_execution_time = time.time() - tool_start_time
121
+
122
+ logger.info(f"✅ Tool '{tool_name}' executed successfully in {tool_execution_time:.3f}s")
123
+ logger.debug(f"🔧 Tool result: {tool_result}")
124
+
125
+ wrapped_result = wrap_tool_result(tool_name, tool_result)
126
+
127
+ # Log the conversation
128
+ self._log_conversation(agent_id, message, wrapped_result, tool_used=tool_name)
129
+
130
+ return wrapped_result
131
+
132
+ except Exception as e:
133
+ error_msg = f"Tool '{tool_name}' execution failed: {str(e)}"
134
+ logger.error(f"❌ {error_msg}")
135
+ error_response = {"error": error_msg}
136
+ self._log_conversation(agent_id, message, error_response, tool_used=tool_name)
137
+ return error_response
138
+ else:
139
+ error_msg = f"Unknown tool requested: '{tool_name}'"
140
+ logger.error(f"❌ {error_msg}")
141
+ logger.debug(f"📊 Available tools: {list(TOOL_REGISTRY.keys())}")
142
+ error_response = {"error": error_msg}
143
+ self._log_conversation(agent_id, message, error_response)
144
+ return error_response
145
+
146
+ # Log successful conversation
147
+ self._log_conversation(agent_id, message, response)
118
148
  return response
119
149
 
120
150
  except Exception as e:
121
- error_response = {
122
- "error": f"Agent {agent_id} failed to handle message: {str(e)}",
123
- "agent_id": agent_id
124
- }
125
- log.error(f"Error sending message to agent {agent_id}: {e}")
151
+ error_msg = f"Agent '{agent_id}' error: {str(e)}"
152
+ logger.error(f" {error_msg}")
153
+ logger.debug(f"🐛 Exception details: {type(e).__name__}: {e}")
154
+ error_response = {"error": error_msg}
155
+ self._log_conversation(agent_id, message, error_response)
126
156
  return error_response
127
-
128
- def broadcast_message(self, message: Dict[str, Any], exclude_agents: List[str] = None) -> Dict[str, Dict[str, Any]]:
157
+
158
+ def broadcast_message(self, message: Dict[str, Any], exclude_agents: Optional[List[str]] = None) -> Dict[str, Dict[str, Any]]:
129
159
  """
130
- Broadcast a message to all registered agents.
160
+ Send a message to all registered agents (optionally excluding some).
131
161
 
132
162
  Args:
133
163
  message: Message to broadcast
134
164
  exclude_agents: List of agent IDs to exclude from broadcast
135
165
 
136
166
  Returns:
137
- Dictionary mapping agent_id to response
167
+ Dict mapping agent IDs to their responses
138
168
  """
139
169
  exclude_agents = exclude_agents or []
140
- responses = {}
170
+ target_agents = [aid for aid in self.agents.keys() if aid not in exclude_agents]
141
171
 
142
- for agent_id in self.agents:
143
- if agent_id not in exclude_agents:
144
- try:
145
- responses[agent_id] = self.send_message(agent_id, message)
146
- except Exception as e:
147
- responses[agent_id] = {"error": str(e)}
148
-
149
- return responses
172
+ logger.info(f"📡 Broadcasting message to {len(target_agents)} agents")
173
+ logger.debug(f"🎯 Target agents: {target_agents}")
174
+ if exclude_agents:
175
+ logger.debug(f"🚫 Excluded agents: {exclude_agents}")
150
176
 
151
- def handle_tool_request(self, tool_name: str, args: Dict[str, Any]) -> Dict[str, Any]:
152
- """
153
- Handle a tool execution request.
177
+ responses = {}
178
+ start_time = time.time()
154
179
 
155
- Args:
156
- tool_name: Name of the tool to execute
157
- args: Arguments for the tool
158
-
159
- Returns:
160
- Tool execution result wrapped in protocol format
161
- """
162
- try:
163
- result = run_tool(tool_name, args)
164
- return wrap_tool_result(tool_name, result)
165
- except Exception as e:
166
- error_result = {
167
- "success": False,
168
- "error": str(e),
169
- "tool_name": tool_name,
170
- "args": args
171
- }
172
- return wrap_tool_result(tool_name, error_result)
173
-
174
- def process_agent_response(self, agent_id: str, response: Any) -> Dict[str, Any]:
175
- """
176
- Process an agent response, handling tool requests and final responses.
180
+ for agent_id in target_agents:
181
+ logger.debug(f"📨 Broadcasting to agent '{agent_id}'")
182
+ responses[agent_id] = self.send_message(agent_id, message)
177
183
 
178
- Args:
179
- agent_id: ID of the agent that sent the response
180
- response: Agent response (string or dict)
181
-
182
- Returns:
183
- Processed response
184
- """
185
- try:
186
- # Parse the agent response
187
- parsed_response = parse_agent_response(response)
188
-
189
- # Check if it's a tool request
190
- if is_tool_request(parsed_response):
191
- tool_name, args = get_tool_request(parsed_response)
192
- log.info(f"Agent {agent_id} requested tool: {tool_name}")
193
-
194
- # Execute the tool
195
- tool_result = self.handle_tool_request(tool_name, args)
196
-
197
- # Log tool execution
198
- self.conversation_history.append({
199
- "type": "tool_execution",
200
- "agent_id": agent_id,
201
- "tool_name": tool_name,
202
- "args": args,
203
- "result": tool_result,
204
- "timestamp": self._get_timestamp()
205
- })
206
-
207
- return tool_result
208
-
209
- # Check if it's a final response
210
- elif is_final_response(parsed_response):
211
- final_response = get_final_response(parsed_response)
212
- log.info(f"Agent {agent_id} sent final response")
213
- return final_response
214
-
215
- else:
216
- # Return the parsed response as-is
217
- return parsed_response
218
-
219
- except Exception as e:
220
- log.error(f"Error processing agent response from {agent_id}: {e}")
221
- return {
222
- "error": f"Failed to process response: {str(e)}",
223
- "original_response": response
224
- }
225
-
226
- def get_conversation_history(self, agent_id: str = None) -> List[Dict[str, Any]]:
184
+ broadcast_time = time.time() - start_time
185
+ logger.info(f"✅ Broadcast completed in {broadcast_time:.3f}s")
186
+
187
+ return responses
188
+
189
+ def get_conversation_history(self, agent_id: Optional[str] = None) -> List[Dict[str, Any]]:
227
190
  """
228
191
  Get conversation history, optionally filtered by agent.
229
192
 
@@ -233,28 +196,53 @@ class Orchestrator:
233
196
  Returns:
234
197
  List of conversation entries
235
198
  """
236
- if agent_id:
237
- return [
199
+ if agent_id is None:
200
+ logger.debug(f"📚 Retrieving full conversation history ({len(self.conversation_history)} entries)")
201
+ return self.conversation_history.copy()
202
+ else:
203
+ filtered_history = [
238
204
  entry for entry in self.conversation_history
239
205
  if entry.get("agent_id") == agent_id
240
206
  ]
241
- return self.conversation_history.copy()
242
-
207
+ logger.debug(f"📚 Retrieving conversation history for '{agent_id}' ({len(filtered_history)} entries)")
208
+ return filtered_history
209
+
243
210
  def clear_history(self) -> None:
244
- """Clear conversation history."""
211
+ """Clear the conversation history."""
212
+ old_count = len(self.conversation_history)
245
213
  self.conversation_history.clear()
246
- log.info("Conversation history cleared")
247
-
214
+ logger.info(f"🗑️ Conversation history cleared ({old_count} entries removed)")
215
+
248
216
  def get_session_info(self) -> Dict[str, Any]:
249
- """Get current session information."""
250
- return {
217
+ """
218
+ Get current session information.
219
+
220
+ Returns:
221
+ Dict containing session metadata
222
+ """
223
+ info = {
251
224
  "session_id": self.session_id,
252
- "registered_agents": self.list_agents(),
253
- "conversation_length": len(self.conversation_history),
254
- "timestamp": self._get_timestamp()
225
+ "registered_agents": list(self.agents.keys()),
226
+ "conversation_count": len(self.conversation_history),
227
+ "available_tools": list(TOOL_REGISTRY.keys())
255
228
  }
229
+ logger.debug(f"📊 Session info requested: {info}")
230
+ return info
231
+
232
+ def _log_conversation(self, agent_id: str, message: Dict[str, Any], response: Dict[str, Any], tool_used: Optional[str] = None) -> None:
233
+ """Log a conversation entry."""
234
+ entry = {
235
+ "timestamp": time.time(),
236
+ "agent_id": agent_id,
237
+ "message": message,
238
+ "response": response,
239
+ "session_id": self.session_id
240
+ }
241
+
242
+ if tool_used:
243
+ entry["tool_used"] = tool_used
244
+ logger.debug(f"💾 Logging conversation with tool usage: {tool_used}")
245
+ else:
246
+ logger.debug(f"💾 Logging conversation entry")
256
247
 
257
- def _get_timestamp(self) -> str:
258
- """Get current timestamp in ISO format."""
259
- from datetime import datetime
260
- return datetime.utcnow().isoformat() + "Z"
248
+ self.conversation_history.append(entry)
dacp/tools.py CHANGED
@@ -1,21 +1,43 @@
1
+ import logging
1
2
  from typing import Dict, Any, Callable
2
3
  from pathlib import Path
3
4
 
5
+ # Set up logger for this module
6
+ logger = logging.getLogger("dacp.tools")
7
+
4
8
  TOOL_REGISTRY: Dict[str, Callable[..., Dict[str, Any]]] = {}
5
9
 
6
10
 
7
11
  def register_tool(tool_id: str, func: Callable[..., Dict[str, Any]]) -> None:
8
12
  """Register a tool function."""
9
13
  TOOL_REGISTRY[tool_id] = func
14
+ logger.info(f"🔧 Tool '{tool_id}' registered successfully (function: {func.__name__})")
15
+ logger.debug(f"📊 Total registered tools: {len(TOOL_REGISTRY)}")
10
16
 
11
17
 
12
18
  def run_tool(tool_id: str, args: Dict[str, Any]) -> Dict[str, Any]:
13
19
  """Run a registered tool with the given arguments."""
14
20
  if tool_id not in TOOL_REGISTRY:
21
+ logger.error(f"❌ Unknown tool requested: '{tool_id}'")
22
+ logger.debug(f"📊 Available tools: {list(TOOL_REGISTRY.keys())}")
15
23
  raise ValueError(f"Unknown tool: {tool_id}")
16
24
 
17
25
  tool_func = TOOL_REGISTRY[tool_id]
18
- return tool_func(**args)
26
+ logger.debug(f"🛠️ Executing tool '{tool_id}' with args: {args}")
27
+
28
+ import time
29
+ start_time = time.time()
30
+
31
+ try:
32
+ result = tool_func(**args)
33
+ execution_time = time.time() - start_time
34
+ logger.info(f"✅ Tool '{tool_id}' executed successfully in {execution_time:.3f}s")
35
+ logger.debug(f"🔧 Tool result: {result}")
36
+ return result
37
+ except Exception as e:
38
+ execution_time = time.time() - start_time
39
+ logger.error(f"❌ Tool '{tool_id}' failed after {execution_time:.3f}s: {type(e).__name__}: {e}")
40
+ raise
19
41
 
20
42
 
21
43
  def file_writer(path: str, content: str) -> Dict[str, Any]:
@@ -29,20 +51,27 @@ def file_writer(path: str, content: str) -> Dict[str, Any]:
29
51
  Returns:
30
52
  Dict with success status and file path
31
53
  """
54
+ logger.debug(f"📝 Writing to file: {path} ({len(content)} characters)")
55
+
32
56
  try:
33
57
  # Create parent directories if they don't exist
34
- Path(path).parent.mkdir(parents=True, exist_ok=True)
58
+ parent_dir = Path(path).parent
59
+ if not parent_dir.exists():
60
+ logger.debug(f"📁 Creating parent directories: {parent_dir}")
61
+ parent_dir.mkdir(parents=True, exist_ok=True)
35
62
 
36
63
  # Write the content to the file
37
64
  with open(path, "w", encoding="utf-8") as f:
38
65
  f.write(content)
39
66
 
67
+ logger.info(f"✅ File written successfully: {path}")
40
68
  return {
41
69
  "success": True,
42
70
  "path": path,
43
71
  "message": f"Successfully wrote {len(content)} characters to {path}",
44
72
  }
45
73
  except Exception as e:
74
+ logger.error(f"❌ Failed to write file {path}: {type(e).__name__}: {e}")
46
75
  return {
47
76
  "success": False,
48
77
  "path": path,
@@ -52,4 +81,6 @@ def file_writer(path: str, content: str) -> Dict[str, Any]:
52
81
 
53
82
 
54
83
  # Register the built-in file_writer tool
84
+ logger.debug("🏗️ Registering built-in tools...")
55
85
  register_tool("file_writer", file_writer)
86
+ logger.debug("✅ Built-in tools registration complete")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dacp
3
- Version: 0.3.0
3
+ Version: 0.3.1
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
@@ -132,6 +132,16 @@ response = dacp.call_llm("What is the weather like today?")
132
132
 
133
133
  - `call_llm(prompt: str, model: str = "gpt-4") -> str`: Call OpenAI (legacy function)
134
134
 
135
+ ### Logging
136
+
137
+ - `enable_info_logging(log_file: str = None) -> None`: Enable info-level logging with emoji format
138
+ - `enable_debug_logging(log_file: str = None) -> None`: Enable debug logging with detailed format
139
+ - `enable_quiet_logging() -> None`: Enable only error and critical logging
140
+ - `setup_dacp_logging(level, format_style, include_timestamp, log_file) -> None`: Custom logging setup
141
+ - `set_dacp_log_level(level: str) -> None`: Change log level dynamically
142
+ - `disable_dacp_logging() -> None`: Disable all DACP logging
143
+ - `enable_dacp_logging() -> None`: Re-enable DACP logging
144
+
135
145
  ### Protocol
136
146
 
137
147
  - `parse_agent_response(response: str | dict) -> dict`: Parse agent response
@@ -348,6 +358,91 @@ else:
348
358
  - ✅ Returns detailed success/error information
349
359
  - ✅ Safe error handling
350
360
 
361
+ ## Logging
362
+
363
+ DACP includes comprehensive logging to help you monitor agent operations, tool executions, and intelligence calls.
364
+
365
+ ### Quick Setup
366
+
367
+ ```python
368
+ import dacp
369
+
370
+ # Enable info-level logging with emoji format (recommended for production)
371
+ dacp.enable_info_logging()
372
+
373
+ # Enable debug logging for development (shows detailed information)
374
+ dacp.enable_debug_logging()
375
+
376
+ # Enable quiet logging (errors only)
377
+ dacp.enable_quiet_logging()
378
+ ```
379
+
380
+ ### Custom Configuration
381
+
382
+ ```python
383
+ # Full control over logging configuration
384
+ dacp.setup_dacp_logging(
385
+ level="INFO", # DEBUG, INFO, WARNING, ERROR, CRITICAL
386
+ format_style="emoji", # "simple", "detailed", "emoji"
387
+ include_timestamp=True, # Include timestamps
388
+ log_file="dacp.log" # Optional: also log to file
389
+ )
390
+
391
+ # Change log level dynamically
392
+ dacp.set_dacp_log_level("DEBUG")
393
+
394
+ # Disable/enable logging
395
+ dacp.disable_dacp_logging()
396
+ dacp.enable_dacp_logging()
397
+ ```
398
+
399
+ ### What Gets Logged
400
+
401
+ With logging enabled, you'll see:
402
+
403
+ - **🎭 Agent Registration**: When agents are registered/unregistered
404
+ - **📨 Message Routing**: Messages sent to agents and broadcast operations
405
+ - **🔧 Tool Execution**: Tool calls, execution time, and results
406
+ - **🧠 Intelligence Calls**: LLM provider calls, configuration, and performance
407
+ - **❌ Errors**: Detailed error information with context
408
+ - **📊 Performance**: Execution times for operations
409
+
410
+ ### Log Format Examples
411
+
412
+ **Emoji Format** (clean, production-friendly):
413
+ ```
414
+ 2025-07-02 09:54:58 - 🎭 Orchestrator initialized with session ID: session_1751414098
415
+ 2025-07-02 09:54:58 - ✅ Agent 'demo-agent' registered successfully (type: MyAgent)
416
+ 2025-07-02 09:54:58 - 📨 Sending message to agent 'demo-agent'
417
+ 2025-07-02 09:54:58 - 🔧 Agent 'demo-agent' requested tool execution
418
+ 2025-07-02 09:54:58 - 🛠️ Executing tool: 'file_writer' with args: {...}
419
+ 2025-07-02 09:54:58 - ✅ Tool 'file_writer' executed successfully in 0.001s
420
+ ```
421
+
422
+ **Detailed Format** (development/debugging):
423
+ ```
424
+ 2025-07-02 09:54:58 - dacp.orchestrator:89 - INFO - 📨 Sending message to agent 'demo-agent'
425
+ 2025-07-02 09:54:58 - dacp.orchestrator:90 - DEBUG - 📋 Message content: {'task': 'greet'}
426
+ 2025-07-02 09:54:58 - dacp.tools:26 - DEBUG - 🛠️ Executing tool 'file_writer' with args: {...}
427
+ ```
428
+
429
+ ### Example Usage
430
+
431
+ ```python
432
+ import dacp
433
+
434
+ # Enable logging
435
+ dacp.enable_info_logging()
436
+
437
+ # Create and use components - logging happens automatically
438
+ orchestrator = dacp.Orchestrator()
439
+ agent = MyAgent()
440
+ orchestrator.register_agent("my-agent", agent)
441
+
442
+ # This will log the message sending, tool execution, etc.
443
+ response = orchestrator.send_message("my-agent", {"task": "process"})
444
+ ```
445
+
351
446
  ## Development
352
447
 
353
448
  ```bash
@@ -0,0 +1,15 @@
1
+ dacp/__init__.py,sha256=qTwsfYAnuq4PiE_1Vm6gK7VAycBEz_K6C2hzmPOODI0,1352
2
+ dacp/exceptions.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ dacp/intelligence.py,sha256=dyVxbVHAX56tsgC-_C9jNTov9PstPTiGehBS4L57lXw,15002
4
+ dacp/llm.py,sha256=JxHqM-aIm9pAMcVHQevbJGxrlBH4uV1ngRQdvyp9L3A,827
5
+ dacp/logging_config.py,sha256=FqQp650BwQLKM32L0ITYjadXXzG22KbjsL21_JlK9LM,3950
6
+ dacp/main.py,sha256=ZcJLymC9S5A4iO4yV7X178RLlhDrDuAwirdevUD5Yn0,470
7
+ dacp/orchestrator.py,sha256=oJ0C27qMBVgAW8jPqTvNhVOuaYBn5wRa2kJIej05iac,10065
8
+ dacp/protocol.py,sha256=DVhLTdyDVlAu8ETSEX8trPeycKfMeirHwcWQ8-BY7eA,1026
9
+ dacp/tools.py,sha256=9YNBg-YJtAWKNo88VXgQ6bedu_4Z3pGWq2QWVXPJg30,3009
10
+ dacp/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ dacp-0.3.1.dist-info/licenses/LICENSE,sha256=tb5kgUYRypHqAy8wlrJUBSYI5l1SBmawSYHmCC-MVW0,1074
12
+ dacp-0.3.1.dist-info/METADATA,sha256=CAs6fi58DLlSzcKkn8uPMKd1QP19yPWbFNKF71Z8Q5s,14506
13
+ dacp-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
14
+ dacp-0.3.1.dist-info/top_level.txt,sha256=Qxy0cy5jl7ttTQoGFlY9LXB6CbSvsekJ2y0P8I7L1zA,5
15
+ dacp-0.3.1.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- dacp/__init__.py,sha256=-EFiHyOWg8IcG2FI-Hmd9wrHicGi8qAMv0cPwz0oCiU,833
2
- dacp/exceptions.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- dacp/intelligence.py,sha256=SGLaq6dlJmeDqP0ZgT6bR_4WahNf-K7qWBaTG3yqBMI,9487
4
- dacp/llm.py,sha256=JxHqM-aIm9pAMcVHQevbJGxrlBH4uV1ngRQdvyp9L3A,827
5
- dacp/main.py,sha256=ZcJLymC9S5A4iO4yV7X178RLlhDrDuAwirdevUD5Yn0,470
6
- dacp/orchestrator.py,sha256=PIur8Kts-vtUchmo7E8B59ZLm6s7C7yQ0ScK9E5FXhE,8756
7
- dacp/protocol.py,sha256=DVhLTdyDVlAu8ETSEX8trPeycKfMeirHwcWQ8-BY7eA,1026
8
- dacp/tools.py,sha256=FLgZa5Brni9H3Hyn336k3DGoVxIa_1rFM4WpIRXzVbc,1569
9
- dacp/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- dacp-0.3.0.dist-info/licenses/LICENSE,sha256=tb5kgUYRypHqAy8wlrJUBSYI5l1SBmawSYHmCC-MVW0,1074
11
- dacp-0.3.0.dist-info/METADATA,sha256=J9bKw2rxID--1fqZ9Z33lSs2SKTmat72zVLj-DUirU0,11220
12
- dacp-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
13
- dacp-0.3.0.dist-info/top_level.txt,sha256=Qxy0cy5jl7ttTQoGFlY9LXB6CbSvsekJ2y0P8I7L1zA,5
14
- dacp-0.3.0.dist-info/RECORD,,
File without changes