agnt5 0.2.8a5__cp310-abi3-macosx_10_12_x86_64.whl → 0.2.8a7__cp310-abi3-macosx_10_12_x86_64.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.

Potentially problematic release.


This version of agnt5 might be problematic. Click here for more details.

agnt5/_core.abi3.so CHANGED
Binary file
agnt5/_telemetry.py CHANGED
@@ -73,10 +73,17 @@ class OpenTelemetryHandler(logging.Handler):
73
73
  exc_text = self.formatException(record.exc_info)
74
74
  message = f"{message}\n{exc_text}"
75
75
 
76
+ # Extract correlation IDs from LogRecord attributes (added by _CorrelationFilter)
77
+ # These ensure logs can be correlated with distributed traces in observability backends
78
+ trace_id = getattr(record, 'trace_id', None)
79
+ span_id = getattr(record, 'span_id', None)
80
+ run_id = getattr(record, 'run_id', None)
81
+
76
82
  # Forward to Rust tracing system
77
83
  # Rust side will:
78
84
  # - Add to current span context (inherits invocation.id)
79
- # - Send to OTLP exporter
85
+ # - Attach correlation IDs as span attributes for OTLP export
86
+ # - Send to OTLP exporter with trace context
80
87
  # - Print to console via fmt layer
81
88
  self._log_from_python(
82
89
  level=record.levelname,
@@ -84,7 +91,10 @@ class OpenTelemetryHandler(logging.Handler):
84
91
  target=record.name,
85
92
  module_path=record.module,
86
93
  filename=record.pathname,
87
- line=record.lineno
94
+ line=record.lineno,
95
+ trace_id=trace_id,
96
+ span_id=span_id,
97
+ run_id=run_id,
88
98
  )
89
99
  except Exception:
90
100
  # Don't let logging errors crash the application
agnt5/agent.py CHANGED
@@ -10,7 +10,7 @@ import functools
10
10
  import json
11
11
  import logging
12
12
  import time
13
- from typing import Any, Callable, Dict, List, Optional
13
+ from typing import Any, Callable, Dict, List, Optional, Union
14
14
 
15
15
  from .context import Context
16
16
  from . import lm
@@ -86,7 +86,6 @@ class AgentContext(Context):
86
86
  if state_manager:
87
87
  # Explicit state adapter provided (parameter name kept for backward compat)
88
88
  self._state_adapter = state_manager
89
- logger.debug(f"AgentContext using provided state adapter")
90
89
  elif parent_context:
91
90
  # Try to inherit state adapter from parent
92
91
  try:
@@ -94,38 +93,30 @@ class AgentContext(Context):
94
93
  if hasattr(parent_context, '_workflow_entity'):
95
94
  # WorkflowContext - get state adapter from worker context
96
95
  self._state_adapter = _get_state_adapter()
97
- logger.debug(f"AgentContext inheriting state from WorkflowContext")
98
96
  elif hasattr(parent_context, '_state_adapter'):
99
97
  # Parent AgentContext - share state adapter
100
98
  self._state_adapter = parent_context._state_adapter
101
- logger.debug(f"AgentContext inheriting state from parent AgentContext")
102
99
  elif hasattr(parent_context, '_state_manager'):
103
100
  # Backward compatibility: parent has old _state_manager
104
101
  self._state_adapter = parent_context._state_manager
105
- logger.debug(f"AgentContext inheriting state from parent (legacy)")
106
102
  else:
107
103
  # FunctionContext or base Context - create new state adapter
108
104
  self._state_adapter = EntityStateAdapter()
109
- logger.debug(f"AgentContext created new state adapter (parent has no state)")
110
105
  except RuntimeError as e:
111
106
  # _get_state_adapter() failed (not in worker context) - create standalone
112
107
  self._state_adapter = EntityStateAdapter()
113
- logger.debug(f"AgentContext created standalone state adapter (not in worker context)")
114
108
  else:
115
109
  # Try to get from worker context first
116
110
  try:
117
111
  self._state_adapter = _get_state_adapter()
118
- logger.debug(f"AgentContext got state adapter from worker context")
119
112
  except RuntimeError as e:
120
113
  # Standalone - create new state adapter
121
114
  self._state_adapter = EntityStateAdapter()
122
- logger.debug(f"AgentContext created standalone state adapter")
123
115
 
124
116
  # Conversation key for state storage (used for in-memory state)
125
117
  self._conversation_key = f"agent:{agent_name}:{self._session_id}:messages"
126
118
  # Entity key for database persistence (without :messages suffix to match API expectations)
127
119
  self._entity_key = f"agent:{agent_name}:{self._session_id}"
128
- logger.debug(f"AgentContext initialized - session_id={self._session_id}")
129
120
 
130
121
  @property
131
122
  def state(self):
@@ -174,15 +165,12 @@ class AgentContext(Context):
174
165
  if isinstance(session_data, dict) and "messages" in session_data:
175
166
  # New format with session metadata
176
167
  messages_data = session_data["messages"]
177
- logger.debug(f"Loaded {len(messages_data)} messages from session {entity_key}")
178
168
  elif isinstance(session_data, list):
179
169
  # Old format - just messages array
180
170
  messages_data = session_data
181
- logger.debug(f"Loaded {len(messages_data)} messages (legacy format)")
182
171
  else:
183
172
  # No messages found
184
173
  messages_data = []
185
- logger.debug(f"No conversation history found for {entity_key}")
186
174
 
187
175
  # Convert dict representations back to Message objects
188
176
  messages = []
@@ -215,8 +203,6 @@ class AgentContext(Context):
215
203
  Args:
216
204
  messages: List of Message objects to persist
217
205
  """
218
- logger.debug(f"Saving {len(messages)} messages to conversation history")
219
-
220
206
  # Convert Message objects to dict for JSON serialization
221
207
  messages_data = []
222
208
  for msg in messages:
@@ -360,16 +346,23 @@ class Handoff:
360
346
  ```python
361
347
  specialist = Agent(name="specialist", ...)
362
348
 
363
- # Create handoff configuration
364
- handoff_to_specialist = Handoff(
365
- agent=specialist,
366
- description="Transfer to specialist for detailed analysis"
349
+ # Simple: Pass agent directly (auto-wrapped with defaults)
350
+ coordinator = Agent(
351
+ name="coordinator",
352
+ handoffs=[specialist] # Agent auto-converted to Handoff
367
353
  )
368
354
 
369
- # Use in coordinator agent
355
+ # Advanced: Use Handoff for custom configuration
370
356
  coordinator = Agent(
371
357
  name="coordinator",
372
- handoffs=[handoff_to_specialist]
358
+ handoffs=[
359
+ Handoff(
360
+ agent=specialist,
361
+ description="Custom description for LLM",
362
+ tool_name="custom_transfer_name",
363
+ pass_full_history=False
364
+ )
365
+ ]
373
366
  )
374
367
  ```
375
368
  """
@@ -447,7 +440,6 @@ class AgentRegistry:
447
440
  if agent.name in _AGENT_REGISTRY:
448
441
  logger.warning(f"Overwriting existing agent '{agent.name}'")
449
442
  _AGENT_REGISTRY[agent.name] = agent
450
- logger.debug(f"Registered agent '{agent.name}'")
451
443
 
452
444
  @staticmethod
453
445
  def get(name: str) -> Optional["Agent"]:
@@ -463,7 +455,6 @@ class AgentRegistry:
463
455
  def clear() -> None:
464
456
  """Clear all registered agents."""
465
457
  _AGENT_REGISTRY.clear()
466
- logger.debug("Cleared agent registry")
467
458
 
468
459
 
469
460
  class AgentResult:
@@ -528,7 +519,7 @@ class Agent:
528
519
  model: Any, # Can be string like "openai/gpt-4o-mini" OR LanguageModel instance
529
520
  instructions: str,
530
521
  tools: Optional[List[Any]] = None,
531
- handoffs: Optional[List[Handoff]] = None,
522
+ handoffs: Optional[List[Union["Agent", Handoff]]] = None, # Accept Agent or Handoff instances
532
523
  temperature: float = 0.7,
533
524
  max_tokens: Optional[int] = None,
534
525
  top_p: Optional[float] = None,
@@ -543,7 +534,7 @@ class Agent:
543
534
  model: Model string with provider prefix (e.g., "openai/gpt-4o-mini") OR LanguageModel instance
544
535
  instructions: System instructions for the agent
545
536
  tools: List of tools available to the agent (functions, Tool instances, or Agent instances)
546
- handoffs: List of Handoff configurations for agent-to-agent delegation
537
+ handoffs: List of handoff configurations - can be Agent instances (auto-wrapped) or Handoff instances for custom config
547
538
  temperature: LLM temperature (0.0 to 1.0)
548
539
  max_tokens: Maximum tokens to generate
549
540
  top_p: Nucleus sampling parameter
@@ -573,8 +564,18 @@ class Agent:
573
564
  else:
574
565
  raise TypeError(f"model must be a string or LanguageModel instance, got {type(model)}")
575
566
 
576
- # Store handoffs for building handoff tools
577
- self.handoffs = handoffs or []
567
+ # Normalize handoffs: convert Agent instances to Handoff instances
568
+ self.handoffs: List[Handoff] = []
569
+ if handoffs:
570
+ for handoff_item in handoffs:
571
+ if isinstance(handoff_item, Agent):
572
+ # Auto-wrap Agent in Handoff with sensible defaults
573
+ self.handoffs.append(Handoff(agent=handoff_item))
574
+ logger.info(f"Auto-wrapped agent '{handoff_item.name}' in Handoff for '{self.name}'")
575
+ elif isinstance(handoff_item, Handoff):
576
+ self.handoffs.append(handoff_item)
577
+ else:
578
+ raise TypeError(f"handoffs must contain Agent or Handoff instances, got {type(handoff_item)}")
578
579
 
579
580
  # Build tool registry (includes regular tools, agent-as-tools, and handoff tools)
580
581
  self.tools: Dict[str, Tool] = {}
agnt5/worker.py CHANGED
@@ -612,7 +612,6 @@ class Worker:
612
612
  elif component_type == "function":
613
613
  function_config = FunctionRegistry.get(component_name)
614
614
  if function_config:
615
- logger.info(f"🔥 WORKER: Received request for function: {component_name}")
616
615
  # Return coroutine, don't await it
617
616
  return self._execute_function(function_config, input_data, request)
618
617
 
@@ -637,7 +636,6 @@ class Worker:
637
636
  from ._core import PyExecuteComponentResponse
638
637
 
639
638
  exec_start = time.time()
640
- logger.info(f"🔥 WORKER: Executing function {config.name}")
641
639
 
642
640
  try:
643
641
  # Parse input data
@@ -655,26 +653,15 @@ class Worker:
655
653
  runtime_context=request.runtime_context,
656
654
  )
657
655
 
658
- # Create span for function execution with trace linking
659
- from ._core import create_span
660
-
661
- with create_span(
662
- config.name,
663
- "function",
664
- request.runtime_context,
665
- {
666
- "function.name": config.name,
667
- "service.name": self.service_name,
668
- },
669
- ) as span:
670
- # Execute function
671
- if input_dict:
672
- result = config.handler(ctx, **input_dict)
673
- else:
674
- result = config.handler(ctx)
675
-
676
- # Debug: Log what type result is
677
- logger.info(f"🔥 WORKER: Function result type: {type(result).__name__}, isasyncgen: {inspect.isasyncgen(result)}, iscoroutine: {inspect.iscoroutine(result)}")
656
+ # Execute function directly - Rust bridge handles tracing
657
+ # Note: Removed Python-level span creation to avoid duplicate spans.
658
+ # The Rust worker bridge (sdk-python/rust-src/worker.rs:413-659) already
659
+ # creates a comprehensive OpenTelemetry span with all necessary attributes.
660
+ # See DUPLICATE_SPANS_FIX.md for details.
661
+ if input_dict:
662
+ result = config.handler(ctx, **input_dict)
663
+ else:
664
+ result = config.handler(ctx)
678
665
 
679
666
  # Note: Removed flush_telemetry_py() call here - it was causing 2-second blocking delay!
680
667
  # The batch span processor handles flushing automatically with 5s timeout
@@ -842,23 +829,14 @@ class Worker:
842
829
  runtime_context=request.runtime_context,
843
830
  )
844
831
 
845
- # Create span for workflow execution with trace linking
846
- from ._core import create_span
847
-
848
- with create_span(
849
- config.name,
850
- "workflow",
851
- request.runtime_context,
852
- {
853
- "workflow.name": config.name,
854
- "service.name": self.service_name,
855
- },
856
- ) as span:
857
- # Execute workflow
858
- if input_dict:
859
- result = await config.handler(ctx, **input_dict)
860
- else:
861
- result = await config.handler(ctx)
832
+ # Execute workflow directly - Rust bridge handles tracing
833
+ # Note: Removed Python-level span creation to avoid duplicate spans.
834
+ # The Rust worker bridge creates comprehensive OpenTelemetry spans.
835
+ # See DUPLICATE_SPANS_FIX.md for details.
836
+ if input_dict:
837
+ result = await config.handler(ctx, **input_dict)
838
+ else:
839
+ result = await config.handler(ctx)
862
840
 
863
841
  # Note: Removed flush_telemetry_py() call here - it was causing 2-second blocking delay!
864
842
  # The batch span processor handles flushing automatically with 5s timeout
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agnt5
3
- Version: 0.2.8a5
3
+ Version: 0.2.8a7
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,12 +1,12 @@
1
- agnt5-0.2.8a5.dist-info/METADATA,sha256=0yneaLrJFbpRR65wwR3XBaUy-KsJDFoi191gMrC1558,996
2
- agnt5-0.2.8a5.dist-info/WHEEL,sha256=eZxluNosN814qqPoiTnB1GwMrzvnR_7wE3Goh6BHRg8,105
1
+ agnt5-0.2.8a7.dist-info/METADATA,sha256=QrRLobueytjiXx54BwGSm85R9hTLSXoE1CMf4I8-8eE,996
2
+ agnt5-0.2.8a7.dist-info/WHEEL,sha256=eZxluNosN814qqPoiTnB1GwMrzvnR_7wE3Goh6BHRg8,105
3
3
  agnt5/__init__.py,sha256=liMb9egh56qvgY4Xvs9s7grOzF3lXSE8-nIksJLNAy4,2195
4
4
  agnt5/_compat.py,sha256=BGuy3v5VDOHVa5f3Z-C22iMN19lAt0mPmXwF3qSSWxI,369
5
- agnt5/_core.abi3.so,sha256=ArUWjUY6gmhAl70OyRIBDlrqHl6a6xGbip8lMofYAig,12852128
5
+ agnt5/_core.abi3.so,sha256=tO7UsopesF7tyRW_ao3nvK_Hf5NB6BsdsKDhVpxYj8c,12810632
6
6
  agnt5/_retry_utils.py,sha256=loHsWY5BR4wZy57IzcDEjQAy88DHVwVIr25Cn1d9GPA,5801
7
7
  agnt5/_schema_utils.py,sha256=MR67RW757T4Oq2Jqf4kB61H_b51zwaf3CLWELnkngRo,9572
8
- agnt5/_telemetry.py,sha256=bIY9AvBRjJBTHoBPbfR6X1OgaiUf-T0vCoi0_snsWXA,5957
9
- agnt5/agent.py,sha256=PuRq4cA8kJrBgrjRuDu62GBKJwefEjvndJZOj78_OGg,43293
8
+ agnt5/_telemetry.py,sha256=gx4TQNqxeQwpyPWvgVVknPjx5NbenmR6E-DGCj18Ssw,6510
9
+ agnt5/agent.py,sha256=ccV0rLj_9eF_G2VfrY8GWDBbNBadmDAYPrBJ6hMeuTE,43089
10
10
  agnt5/client.py,sha256=kXksazgxdVXWaG9OkjJA4cWruNtcS-ENhtnkrIdw-Nk,23212
11
11
  agnt5/context.py,sha256=S2OzPkhn_jnqSWfT21mSYOux8vHaLKQxcAvggZDHQek,2378
12
12
  agnt5/entity.py,sha256=AlHmSHVxQD5EYBvkmERKUkwv0ERrKaT8rvRK611hv_I,28941
@@ -17,6 +17,6 @@ agnt5/tool.py,sha256=dkShd97Y1cwSOUnTwvL2gr0CW-usRlaq4frki9kREXI,18008
17
17
  agnt5/tracing.py,sha256=Mh2-OfnQM61lM_P8gxJstafdsUA8Gxoo1lP-Joxhub8,5980
18
18
  agnt5/types.py,sha256=Zb71ZMwvrt1p4SH18cAKunp2y5tao_W5_jGYaPDejQo,2840
19
19
  agnt5/version.py,sha256=rOq1mObLihnnKgKqBrwZA0zwOPudEKVFcW1a48ynkqc,573
20
- agnt5/worker.py,sha256=W5_yvy1vcflYjoPAGcIirbHXMbEXijXPJtGQOgl6oz4,51815
20
+ agnt5/worker.py,sha256=jRguDRF0uTjYAmmAgmn3GtdEvIxgTuUoIOsme3ba6mU,51172
21
21
  agnt5/workflow.py,sha256=cDxKK21mLrsgjLGmosinhKnAme30CoQqs_fUFvRsyI0,23456
22
- agnt5-0.2.8a5.dist-info/RECORD,,
22
+ agnt5-0.2.8a7.dist-info/RECORD,,