pyagentic-core 2.2.0a2__tar.gz → 2.2.1__tar.gz

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.
Files changed (45) hide show
  1. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/PKG-INFO +1 -1
  2. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/_agent/_agent.py +23 -31
  3. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/_agent/_agent_state.py +5 -8
  4. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/_info.py +1 -0
  5. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/_spec.py +9 -2
  6. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic_core.egg-info/PKG-INFO +1 -1
  7. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyproject.toml +1 -1
  8. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/LICENSE +0 -0
  9. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/README.md +0 -0
  10. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/__init__.py +0 -0
  11. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/__init__.py +0 -0
  12. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/_agent/__init__.py +0 -0
  13. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/_agent/_agent_linking.py +0 -0
  14. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/_exceptions.py +0 -0
  15. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/_metaclasses.py +0 -0
  16. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/_ref.py +0 -0
  17. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/_state.py +0 -0
  18. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/_tool.py +0 -0
  19. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_base/_validation.py +0 -0
  20. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_utils/_typing.py +0 -0
  21. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/_utils/_warnings.py +0 -0
  22. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/llm/__init__.py +0 -0
  23. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/llm/_anthropic.py +0 -0
  24. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/llm/_gemini.py +0 -0
  25. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/llm/_mock.py +0 -0
  26. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/llm/_openai.py +0 -0
  27. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/llm/_openaiv1.py +0 -0
  28. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/llm/_provider.py +0 -0
  29. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/logging.py +0 -0
  30. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/models/llm.py +0 -0
  31. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/models/response.py +0 -0
  32. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/models/tracing.py +0 -0
  33. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/policies/__init__.py +0 -0
  34. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/policies/_events.py +0 -0
  35. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/policies/_policy.py +0 -0
  36. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/tracing/__init__.py +0 -0
  37. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/tracing/_basic.py +0 -0
  38. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/tracing/_langfuse.py +0 -0
  39. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/tracing/_tracer.py +0 -0
  40. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic/updates.py +0 -0
  41. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic_core.egg-info/SOURCES.txt +0 -0
  42. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic_core.egg-info/dependency_links.txt +0 -0
  43. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic_core.egg-info/requires.txt +0 -0
  44. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/pyagentic_core.egg-info/top_level.txt +0 -0
  45. {pyagentic_core-2.2.0a2 → pyagentic_core-2.2.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyagentic-core
3
- Version: 2.2.0a2
3
+ Version: 2.2.1
4
4
  Summary: Build LLM Agents in a Pythonic way
5
5
  Author-email: Ryan Mikulec <rmikulec.dev@gmail.com>
6
6
  License: MIT
@@ -1,6 +1,5 @@
1
1
  import inspect
2
2
  import json
3
- import asyncio
4
3
  from functools import wraps
5
4
  from typing import (
6
5
  Callable,
@@ -463,8 +462,10 @@ class BaseAgent(metaclass=AgentMeta):
463
462
 
464
463
  # Add all @tool decorated methods
465
464
  for tool_def in self.__tool_defs__.values():
465
+ if tool_def.condition:
466
+ if not tool_def.condition(self.state):
467
+ continue
466
468
  # Resolve StateRefs in parameters (e.g., ref.self.user_name -> actual value)
467
-
468
469
  if self.phases and tool_def.phases:
469
470
  if self.state.phase in tool_def.phases:
470
471
  tool_defs.append(tool_def.resolve(self.agent_reference))
@@ -473,8 +474,18 @@ class BaseAgent(metaclass=AgentMeta):
473
474
 
474
475
  # Add linked agents as tools
475
476
  for name, linked_def in self.__linked_agents__.items():
476
- tool_def = linked_def.agent.get_tool_definition(name)
477
- tool_defs.append(tool_def.resolve(self.agent_reference))
477
+
478
+ if linked_def.info.condition:
479
+ if not linked_def.info.condition(self.state):
480
+ continue
481
+
482
+ if self.phases and linked_def.info.phases:
483
+ if self.state.phase in linked_def.info.phases:
484
+ tool_def = linked_def.agent.get_tool_definition(name)
485
+ tool_defs.append(tool_def.resolve(self.agent_reference))
486
+ else:
487
+ tool_def = linked_def.agent.get_tool_definition(name)
488
+ tool_defs.append(tool_def.resolve(self.agent_reference))
478
489
 
479
490
  return tool_defs
480
491
 
@@ -549,43 +560,24 @@ class BaseAgent(metaclass=AgentMeta):
549
560
  self.state._messages.append(Message(role="assistant", content=response.text))
550
561
  break
551
562
 
552
- tasks = []
553
-
554
- async def wrap(kind: str, tool_call, coro):
555
- """Run the coroutine and attach metadata."""
556
- result = await coro
557
- return kind, tool_call, result
558
-
563
+ # Execute all tool/agent calls from this response
559
564
  for tool_call in response.tool_calls:
565
+ # Skip if we've already processed this call (prevents duplicates)
560
566
  if tool_call.id and tool_call.id in processed_call_ids:
561
567
  continue
562
568
 
563
569
  processed_call_ids.add(tool_call.id)
564
570
 
571
+ # Route to either @tool methods or linked agents
565
572
  if tool_call.name in self.__tool_defs__:
566
- coro = self._process_tool_call(tool_call, call_depth=depth)
567
- kind = "tool"
573
+ result = await self._process_tool_call(tool_call, call_depth=depth)
574
+ tool_responses.append(result)
575
+ yield result
568
576
 
569
577
  elif tool_call.name in self.__linked_agents__:
570
- coro = self._process_agent_call(tool_call)
571
- kind = "agent"
572
-
573
- else:
574
- continue
575
-
576
- task = asyncio.create_task(wrap(kind, tool_call, coro))
577
- tasks.append(task)
578
-
579
- # Process tasks as they *finish*, not in original order
580
- for task in asyncio.as_completed(tasks):
581
- kind, tool_call, result = await task
582
-
583
- if kind == "tool":
584
- tool_responses.append(result)
585
- else:
578
+ result = await self._process_agent_call(tool_call)
586
579
  agent_responses.append(result)
587
-
588
- yield result
580
+ yield result
589
581
 
590
582
  # Increment depth and continue loop (LLM will see tool results next iteration)
591
583
  depth += 1
@@ -26,6 +26,7 @@ class _AgentState(BaseModel):
26
26
  ("on", EventKind.SET): "on_set",
27
27
  ("background", EventKind.SET): "background_set",
28
28
  }
29
+ _state_lock: ClassVar[threading.Lock] = PrivateAttr(default_factory=threading.Lock)
29
30
  __policies__: ClassVar[dict[str, list[Policy]]]
30
31
 
31
32
  instructions: str
@@ -61,17 +62,14 @@ class _AgentState(BaseModel):
61
62
 
62
63
  def _update_state_machine(self, phases):
63
64
  for to_, from_, condition in phases:
64
- with self._state_lock:
65
- if condition(self) and self.phase == from_:
66
- trigger = f"{to_}_to_{from_}"
67
- getattr(self._machine, trigger)()
65
+ if condition(self):
66
+ trigger = f"{to_}_to_{from_}"
67
+ getattr(self._machine, trigger)()
68
68
 
69
69
  def model_post_init(self, state):
70
70
  self._instructions_template = Template(source=self.instructions)
71
71
  if self.input_template:
72
72
  self._input_template = Template(source=self.input_template)
73
-
74
- self._state_lock = threading.Lock()
75
73
  return super().model_post_init(state)
76
74
 
77
75
  def get_policies(self, state_name: str) -> list[Policy]:
@@ -210,8 +208,7 @@ class _AgentState(BaseModel):
210
208
  event = SetEvent(name=name, previous=previous, value=value)
211
209
  final_value = self._run_policies(event, "on")
212
210
 
213
- with self._state_lock:
214
- setattr(self, name, final_value)
211
+ setattr(self, name, final_value)
215
212
  asyncio.create_task(self._dispatch_policies(event, "background"))
216
213
 
217
214
  @classmethod
@@ -45,6 +45,7 @@ class AgentInfo(_SpecInfo):
45
45
  """
46
46
 
47
47
  condition: MaybeRef[Callable] | None = None
48
+ phases: list[str] | None = None
48
49
 
49
50
 
50
51
  @dataclass
@@ -117,7 +117,10 @@ class spec:
117
117
 
118
118
  @staticmethod
119
119
  def AgentLink(
120
- default: Any = None, default_factory: Callable = None, condition: Callable = None
120
+ default: Any = None,
121
+ default_factory: Callable = None,
122
+ condition: Callable = None,
123
+ phases: list[str] | None = None,
121
124
  ) -> AgentInfo:
122
125
  """
123
126
  Creates an AgentInfo descriptor for configuring linked agent fields.
@@ -126,8 +129,12 @@ class spec:
126
129
  default (Any, optional): The default agent instance
127
130
  default_factory (Callable, optional): A factory function to generate the default agent
128
131
  condition (Callable, optional): A callable determining when this agent link is active
132
+ phases (list[str], optional): A list of phases of when this agent will be available.
133
+ When None, will show for all phases. Defaults to None.
129
134
 
130
135
  Returns:
131
136
  AgentInfo: A configured AgentInfo descriptor
132
137
  """
133
- return AgentInfo(default=default, default_factory=default_factory, condition=condition)
138
+ return AgentInfo(
139
+ default=default, default_factory=default_factory, condition=condition, phases=phases
140
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyagentic-core
3
- Version: 2.2.0a2
3
+ Version: 2.2.1
4
4
  Summary: Build LLM Agents in a Pythonic way
5
5
  Author-email: Ryan Mikulec <rmikulec.dev@gmail.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pyagentic-core"
3
- version = "2.2.0-a.2"
3
+ version = "2.2.1"
4
4
  description = "Build LLM Agents in a Pythonic way"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
File without changes