pyagentic-core 2.15.2.dev2__py3-none-any.whl → 2.16.1.dev1__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.
@@ -128,10 +128,12 @@ class BaseAgent(metaclass=AgentMeta):
128
128
 
129
129
  Agent definition requires the use of special decorators and class attributes:
130
130
  - @tool: Declares a method as a tool callable by the LLM
131
- - __instructions__: Required class attribute defining the agent's instructions,
132
- either as a string or a PromptRef from a PromptEngine. Rendered with state
133
- into the system message sent to the LLM. (__system_message__ is the
134
- deprecated spelling.)
131
+ - __instructions__: Class attribute defining the agent's instructions, either as
132
+ a string or a PromptRef from a PromptEngine. Rendered with state into the
133
+ system message sent to the LLM. Inherited from the nearest ancestor when
134
+ not declared; an overriding declaration can embed the parent's rendered
135
+ instructions with `{{ super }}`. Required somewhere in the hierarchy.
136
+ (__system_message__ is the deprecated spelling.)
135
137
  - __description__: Optional description used when agent is linked to another agent
136
138
  - __input_template__: Optional template for formatting user input
137
139
  - __response_format__: Optional Pydantic model for structured output
@@ -179,8 +181,11 @@ class BaseAgent(metaclass=AgentMeta):
179
181
  __dependencies__: ClassVar[dict[str, type]] # Depends[T] field -> dependency type
180
182
 
181
183
  # User-set Class Attributes (defined in subclass)
182
- __instructions__: ClassVar[Union[str, PromptRef]] # Required: the agent's instructions
184
+ __instructions__: ClassVar[Union[str, PromptRef]] # The agent's instructions (inheritable)
183
185
  __system_message__: ClassVar[str] # Deprecated: old spelling of __instructions__
186
+ # Overridden ancestor instructions, oldest first (set by metaclass); rendered
187
+ # into __instructions__ as `{{ super }}`
188
+ __parent_instructions__: ClassVar[tuple[Union[str, PromptRef], ...]] = ()
184
189
  __description__: ClassVar[str] # Optional: description for linked agents
185
190
  __input_template__: ClassVar[str] = None # Optional: template for user input
186
191
  __response_format__: ClassVar[Type[BaseModel]] = None # Optional: structured output format
@@ -36,6 +36,10 @@ class _AgentState(BaseModel):
36
36
  model_config = ConfigDict(arbitrary_types_allowed=True)
37
37
 
38
38
  instructions: str | PromptRef
39
+ # Instructions of overridden ancestors, oldest first; rendered into the
40
+ # template as `{{ super }}`. Excluded from dumps so it never leaks into
41
+ # template context or serialized state.
42
+ parent_instructions: tuple = Field(default=(), exclude=True)
39
43
  input_template: Optional[str] = "{{ user_message }}"
40
44
 
41
45
  _machine: Machine = PrivateAttr(default=None)
@@ -44,6 +48,7 @@ class _AgentState(BaseModel):
44
48
  _last_usage: Optional[UsageInfo] = PrivateAttr(default=None)
45
49
  _prompt_source: Optional[PromptSource] = PrivateAttr(default=None)
46
50
  _instructions_template: Template = PrivateAttr(default_factory=lambda: Template(source=""))
51
+ _parent_templates: list[Template] = PrivateAttr(default_factory=list)
47
52
  _input_template: Template = PrivateAttr(
48
53
  default_factory=lambda: Template(source="{{ user_message }}")
49
54
  )
@@ -91,6 +96,14 @@ class _AgentState(BaseModel):
91
96
  )
92
97
 
93
98
  self._instructions_template = Template(source=self.instructions)
99
+
100
+ # Templates for overridden ancestor instructions (oldest first); each may
101
+ # itself be a PromptRef, resolved here just like the main instructions
102
+ self._parent_templates = [
103
+ Template(source=parent.resolve().text if isinstance(parent, PromptRef) else parent)
104
+ for parent in self.parent_instructions
105
+ ]
106
+
94
107
  if self.input_template:
95
108
  self._input_template = Template(source=self.input_template)
96
109
 
@@ -417,16 +430,23 @@ class _AgentState(BaseModel):
417
430
  """
418
431
  Returns the current formatted system message with state fields interpolated.
419
432
 
433
+ When the agent overrides an ancestor's instructions, the ancestor chain is
434
+ rendered first (with the same state context) and exposed to each template
435
+ as `{{ super }}`, mirroring template inheritance in Jinja.
436
+
420
437
  Returns:
421
438
  str: The rendered system message with state values
422
439
  """
423
- # start with all the normal dataclass fields
424
-
425
- # now format your instruction template
440
+ context = self.model_dump()
426
441
  if self.phase:
427
- return self._instructions_template.render(phase=self.phase, **self.model_dump())
428
- else:
429
- return self._instructions_template.render(**self.model_dump())
442
+ context["phase"] = self.phase
443
+
444
+ # Fold the ancestor chain oldest-to-newest so each template's `{{ super }}`
445
+ # is its own parent's fully rendered instructions
446
+ rendered = ""
447
+ for template in (*self._parent_templates, self._instructions_template):
448
+ rendered = template.render(**{**context, "super": rendered})
449
+ return rendered
430
450
 
431
451
  @property
432
452
  def messages(self) -> list[Message]:
@@ -18,12 +18,13 @@ class InvalidToolDefinition(Exception):
18
18
  class InstructionsNotDeclared(Exception):
19
19
  """
20
20
  Exception raised when an Agent subclass is created without declaring __instructions__
21
- (or the deprecated __system_message__).
21
+ (or the deprecated __system_message__) and no ancestor declares one to inherit.
22
22
  """
23
23
 
24
24
  def __init__(self):
25
25
  super().__init__(
26
- "Instructions not declared on agent. Agent must be declared with `__instructions__`"
26
+ "Instructions not declared on agent. Agent must be declared with "
27
+ "`__instructions__` or inherit one from a parent agent"
27
28
  )
28
29
 
29
30
 
@@ -611,6 +611,7 @@ class AgentMeta(type):
611
611
  # Create the state object with instructions and state fields
612
612
  self.state = self.__state_class__(
613
613
  instructions=self.__instructions__,
614
+ parent_instructions=self.__parent_instructions__,
614
615
  input_template=self.__input_template__,
615
616
  **compiled,
616
617
  )
@@ -665,7 +666,10 @@ class AgentMeta(type):
665
666
 
666
667
  Inheritance is respected in MRO order. Tools, state attributes, and linked agents
667
668
  can all be inherited from other agents or mixins.
668
- __instructions__ and __input_template__ are *not* inherited.
669
+ __instructions__ is inherited from the nearest ancestor when not declared. When a
670
+ subclass declares its own __instructions__, the ancestor chain is recorded on
671
+ __parent_instructions__ so the template can embed the parent's rendered
672
+ instructions via `{{ super }}`.
669
673
 
670
674
  Args:
671
675
  name (str): Name of the new class
@@ -700,10 +704,11 @@ class AgentMeta(type):
700
704
  mcs.__BaseAgent__ = cls
701
705
  return cls
702
706
  cls.__abstract_base__ = False
703
- # Verify instructions are set (not inherited); __system_message__ is
704
- # the deprecated spelling and normalizes onto __instructions__
707
+ # Resolve instructions; __system_message__ is the deprecated spelling
708
+ # and normalizes onto __instructions__
709
+ declared = None
705
710
  if "__instructions__" in namespace:
706
- cls.__instructions__ = namespace["__instructions__"]
711
+ declared = namespace["__instructions__"]
707
712
  elif "__system_message__" in namespace:
708
713
  warnings.warn(
709
714
  f"`__system_message__` on {name} is deprecated; "
@@ -711,7 +716,27 @@ class AgentMeta(type):
711
716
  DeprecationWarning,
712
717
  stacklevel=2,
713
718
  )
714
- cls.__instructions__ = namespace["__system_message__"]
719
+ declared = namespace["__system_message__"]
720
+
721
+ inherited_instructions = inherited_namespace.get(
722
+ "__instructions__", inherited_namespace.get("__system_message__")
723
+ )
724
+ if declared is not None:
725
+ cls.__instructions__ = declared
726
+ # When overriding an ancestor's instructions, record the ancestor
727
+ # chain (oldest first) so the template can embed the parent's
728
+ # rendered instructions via `{{ super }}`
729
+ if inherited_instructions is not None:
730
+ cls.__parent_instructions__ = (
731
+ *inherited_namespace.get("__parent_instructions__", ()),
732
+ inherited_instructions,
733
+ )
734
+ else:
735
+ cls.__parent_instructions__ = ()
736
+ elif inherited_instructions is not None:
737
+ # Instructions are inherited from the nearest ancestor;
738
+ # __parent_instructions__ resolves to the declaring ancestor's chain
739
+ cls.__instructions__ = inherited_instructions
715
740
  else:
716
741
  raise InstructionsNotDeclared()
717
742
  # Keep the deprecated attribute readable for backwards compatibility
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyagentic-core
3
- Version: 2.15.2.dev2
3
+ Version: 2.16.1.dev1
4
4
  Summary: Build LLM Agents in a Pythonic way
5
5
  Author-email: Ryan Mikulec <rmikulec.dev@gmail.com>
6
6
  License: MIT
@@ -4,10 +4,10 @@ pyagentic/logging.py,sha256=vWLKGx0jZurWQT5pMr6fLH5NgJnZd_eaB97geBnqlwI,1718
4
4
  pyagentic/updates.py,sha256=JrBxbmTRxS-4tfSrai_wPK-dxSyCiNrYwC5MgrzGj54,870
5
5
  pyagentic/_base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  pyagentic/_base/_depends.py,sha256=e9j6GiYvPJAmFExTHMeg-xcFGYvvfF9KtCstX5HDS7Y,2186
7
- pyagentic/_base/_exceptions.py,sha256=Z1AvSEGJu0s8dE6F8iNGBHcNOmwlaS1gA1R15ezQYg4,4298
7
+ pyagentic/_base/_exceptions.py,sha256=2LVKYKjrjcow1rVuWK_CO49npdWP0ii090t0jEJbXHs,4388
8
8
  pyagentic/_base/_info.py,sha256=LeXn3VbEJkP4KmMpjY6bqXjHYnE-ZHLuKoRcrmrqqhs,3020
9
9
  pyagentic/_base/_mcp.py,sha256=jclmFb5yB1szg9PTskPE2hLO3fvnFKJQFnnwTLdf0IY,8327
10
- pyagentic/_base/_metaclasses.py,sha256=jvDuFoz2DAaVxu2vFkAbyT6W61euaDyKW3V0w5dS3kI,37067
10
+ pyagentic/_base/_metaclasses.py,sha256=r51jGJJMXKtO19xJFf1lsjiuhDjIpRZr3YjxJySBIPg,38408
11
11
  pyagentic/_base/_prompts.py,sha256=aSUptdlKhUuJVrIb20FOvICzxp6pcmeb65Xf2goFpvk,9118
12
12
  pyagentic/_base/_ref.py,sha256=E-1DGVoM2xub476BrHOkxTqzdw-8t_N6XuEerXDYYE8,3177
13
13
  pyagentic/_base/_spec.py,sha256=Mx8tXF8ERpsuxizRXuq3wJavbXvCCGUn17YbjiOKP9Y,7670
@@ -15,9 +15,9 @@ pyagentic/_base/_state.py,sha256=-xYVIaKiaU9ERuPf-33nbUhbvI3DgIp36y1bYdYTwJU,179
15
15
  pyagentic/_base/_tool.py,sha256=03VQmY_Q_2NkNJxrHFkAzJJ09679Fb00h8ZHYrYDGUU,11038
16
16
  pyagentic/_base/_validation.py,sha256=BBscZMrXB09LNNP17pYOAY6I4iCW8r2GBVStqBd-9f8,3833
17
17
  pyagentic/_base/_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- pyagentic/_base/_agent/_agent.py,sha256=eyPqISReeTC-yOjva5BNFTs5dr3Qtw-is_yNyt6JWo0,43659
18
+ pyagentic/_base/_agent/_agent.py,sha256=VkWA5Br3d3sFCXAQKZcle-ptO88FY15HyuVRmpKEr8c,44066
19
19
  pyagentic/_base/_agent/_agent_linking.py,sha256=2lVICn9SSk2dgDmdk_awIS7NaSLp-LXvpF_9L3Jaud8,1837
20
- pyagentic/_base/_agent/_agent_state.py,sha256=0YkbUZT-dWHWgBUoMaPjTJ3rNxE-cX0_pIqrLa7nLWM,18628
20
+ pyagentic/_base/_agent/_agent_state.py,sha256=PP3ucelYul87SKe_LWxvoInGxXhz9Zp-wz-RSk9n838,19688
21
21
  pyagentic/_utils/_typing.py,sha256=5aRZZOVzR0ZgnBfejkw__1yoARhn70P5QzA81sxUkls,3681
22
22
  pyagentic/_utils/_warnings.py,sha256=mjlBiYHGnnh5599Gsq5ke8mBFS6WsdhNa7jk20TT9_U,1330
23
23
  pyagentic/api/__init__.py,sha256=7CklNYjxVj5XOyqTWvvWKZU6IYuU8CAfpOhNeGMH1d4,1712
@@ -56,10 +56,10 @@ pyagentic/tracing/__init__.py,sha256=ddMOl_-Nf3WOhu-PYxSJ3kqHZ3eQXAOM5aySn9YmDtA
56
56
  pyagentic/tracing/_basic.py,sha256=jUBKdkOPveCjBzEhHKS_Rvp5l38iZg-5nFIl6xEwOVk,8906
57
57
  pyagentic/tracing/_langfuse.py,sha256=5b5tdT-gyRJP5HDcvCS4tn_k3AFDI6eNsXOd6On5gKQ,13986
58
58
  pyagentic/tracing/_tracer.py,sha256=0uQeqJxPRjfQtvgglF2BPDQM_1fpLBxWB0PpU6KY1eA,8157
59
- pyagentic_core-2.15.2.dev2.dist-info/licenses/LICENSE,sha256=wcOzTj82hOc96HztJk2VzLB2hFHpdIGpjz8vvbpP1_s,1069
60
- pyagentic_core-2.15.2.dev2.dist-info/METADATA,sha256=9gHYz_wiYEPKnw7LsMxfEGbZ_3nARC_z6MVAeHt8if4,8212
61
- pyagentic_core-2.15.2.dev2.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
62
- pyagentic_core-2.15.2.dev2.dist-info/scm_file_list.json,sha256=8UMtz5WpdhOSRNM1zB-dxNzobbueYJYYqfBJoM4n6_w,4883
63
- pyagentic_core-2.15.2.dev2.dist-info/scm_version.json,sha256=6JpJoV9gMgof65-_u6VVITIfQ_efcmI6r_PulZFbolA,165
64
- pyagentic_core-2.15.2.dev2.dist-info/top_level.txt,sha256=lAWfd-ay434uEpSg2FM0ySN0o4vgNGE6D9dJkIhGyfY,10
65
- pyagentic_core-2.15.2.dev2.dist-info/RECORD,,
59
+ pyagentic_core-2.16.1.dev1.dist-info/licenses/LICENSE,sha256=wcOzTj82hOc96HztJk2VzLB2hFHpdIGpjz8vvbpP1_s,1069
60
+ pyagentic_core-2.16.1.dev1.dist-info/METADATA,sha256=xC2nazJjni31ytTVBGZMG9oAqC9Ny12yGpimToki9-o,8212
61
+ pyagentic_core-2.16.1.dev1.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
62
+ pyagentic_core-2.16.1.dev1.dist-info/scm_file_list.json,sha256=8UMtz5WpdhOSRNM1zB-dxNzobbueYJYYqfBJoM4n6_w,4883
63
+ pyagentic_core-2.16.1.dev1.dist-info/scm_version.json,sha256=QBBjEtu7R-9HQ2WE9LnqyJBz06pTR4xHOgjvxXvfNAA,162
64
+ pyagentic_core-2.16.1.dev1.dist-info/top_level.txt,sha256=lAWfd-ay434uEpSg2FM0ySN0o4vgNGE6D9dJkIhGyfY,10
65
+ pyagentic_core-2.16.1.dev1.dist-info/RECORD,,
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "2.16.0a1",
3
+ "distance": 1,
4
+ "node": "gd8ca79a3db1f98addeb3aaff8bd0b760b2986eca",
5
+ "dirty": true,
6
+ "branch": "main",
7
+ "node_date": "2026-07-09"
8
+ }
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "2.15.1.dev1",
3
- "distance": 2,
4
- "node": "g1f06860189326b8709a205b89bbdeb8308b82d07",
5
- "dirty": true,
6
- "branch": "main",
7
- "node_date": "2026-07-09"
8
- }