lionagi 0.16.3__py3-none-any.whl → 0.17.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.
@@ -9,18 +9,12 @@ from pydantic import BaseModel, JsonValue
9
9
 
10
10
  from lionagi.fields.instruct import Instruct
11
11
  from lionagi.models import FieldModel, ModelParams
12
- from lionagi.protocols.types import (
13
- Instruction,
14
- Operative,
15
- Progression,
16
- SenderRecipient,
17
- Step,
18
- ToolRef,
19
- )
12
+ from lionagi.protocols.operatives.step import Operative, Step
13
+ from lionagi.protocols.types import Instruction, Progression, SenderRecipient
20
14
  from lionagi.service.imodel import iModel
21
15
 
22
16
  if TYPE_CHECKING:
23
- from lionagi.session.branch import Branch
17
+ from lionagi.session.branch import Branch, ToolRef
24
18
 
25
19
 
26
20
  def _handle_response_format_kwargs(
@@ -64,8 +58,8 @@ async def operate(
64
58
  image_detail: Literal["low", "high", "auto"] = None,
65
59
  parse_model: iModel = None,
66
60
  skip_validation: bool = False,
67
- tools: ToolRef = None,
68
- operative: Operative = None,
61
+ tools: "ToolRef" = None,
62
+ operative: "Operative" = None,
69
63
  response_format: type[BaseModel] = None, # alias of operative.request_type
70
64
  return_operative: bool = False,
71
65
  actions: bool = False,
@@ -7,7 +7,6 @@ from typing import TYPE_CHECKING, Any, Literal
7
7
  from pydantic import BaseModel
8
8
 
9
9
  from lionagi.ln.fuzzy._fuzzy_validate import fuzzy_validate_mapping
10
- from lionagi.protocols.types import Operative
11
10
  from lionagi.utils import breakdown_pydantic_annotation
12
11
 
13
12
  if TYPE_CHECKING:
@@ -22,7 +21,7 @@ async def parse(
22
21
  ] = "return_value",
23
22
  max_retries: int = 3,
24
23
  request_type: type[BaseModel] = None,
25
- operative: Operative = None,
24
+ operative=None,
26
25
  similarity_algo="jaro_winkler",
27
26
  similarity_threshold: float = 0.85,
28
27
  fuzzy_match: bool = True,
@@ -12,7 +12,6 @@ from .parse.parse import parse
12
12
  from .plan.plan import plan
13
13
  from .ReAct.ReAct import ReAct
14
14
  from .select.select import select
15
- from .translate.translate import translate
16
15
 
17
16
  __all__ = (
18
17
  "brainstorm",
@@ -25,5 +24,4 @@ __all__ = (
25
24
  "operate",
26
25
  "parse",
27
26
  "ReAct",
28
- "translate",
29
27
  )
@@ -2,18 +2,24 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
+ from typing import TYPE_CHECKING
6
+
5
7
  from lionagi.fields.instruct import Instruct
6
- from lionagi.session.session import Branch, Session
8
+
9
+ if TYPE_CHECKING:
10
+ from lionagi.session.session import Branch, Session
7
11
 
8
12
 
9
13
  def prepare_session(
10
- session: Session | None = None,
11
- branch: Branch | None = None,
14
+ session: "Session" = None,
15
+ branch: "Branch" = None,
12
16
  branch_kwargs=None,
13
- ) -> tuple[Session, Branch]:
17
+ ) -> tuple["Session", "Branch"]:
18
+ from lionagi.session.session import Branch, Session
19
+
14
20
  if session is not None:
15
21
  if branch is not None:
16
- branch: Branch = session.branches[branch]
22
+ branch: "Branch" = session.branches[branch]
17
23
  else:
18
24
  branch = session.new_branch(**(branch_kwargs or {}))
19
25
  else:
@@ -18,7 +18,6 @@ from functools import wraps
18
18
  from pathlib import Path
19
19
  from typing import Any, ClassVar, Generic, Literal, TypeVar
20
20
 
21
- import pandas as pd
22
21
  from pydantic import Field, field_serializer
23
22
  from pydantic.fields import FieldInfo
24
23
  from pydapter import Adaptable, AsyncAdaptable
@@ -1047,9 +1046,7 @@ class Pile(Element, Collective[T], Generic[T], Adaptable, AsyncAdaptable):
1047
1046
  kw["adapt_meth"] = "from_dict"
1048
1047
  return await super().adapt_from_async(obj, obj_key, many=many, **kw)
1049
1048
 
1050
- def to_df(
1051
- self, columns: list[str] | None = None, **kw: Any
1052
- ) -> pd.DataFrame:
1049
+ def to_df(self, columns: list[str] | None = None, **kw: Any):
1053
1050
  """Convert to DataFrame."""
1054
1051
  from pydapter.extras.pandas_ import DataFrameAdapter
1055
1052
 
@@ -1207,11 +1204,10 @@ def to_list_type(value: Any, /) -> list[Any]:
1207
1204
 
1208
1205
  if not _ADAPATER_REGISTERED:
1209
1206
  from pydapter.adapters import CsvAdapter, JsonAdapter
1210
- from pydapter.extras.pandas_ import DataFrameAdapter
1211
1207
 
1212
1208
  Pile.register_adapter(CsvAdapter)
1213
1209
  Pile.register_adapter(JsonAdapter)
1214
- Pile.register_adapter(DataFrameAdapter)
1210
+
1215
1211
  _ADAPATER_REGISTERED = True
1216
1212
 
1217
1213
  Pile = Pile
@@ -19,10 +19,8 @@ from .node import Node
19
19
 
20
20
  T = TypeVar("T", bound=Node)
21
21
 
22
- from ._utils import check_matplotlib_available, check_networkx_available
23
-
24
- _NETWORKX_AVAILABLE = check_networkx_available()
25
- _MATPLIB_AVAILABLE = check_matplotlib_available()
22
+ _NETWORKX_AVAILABLE = None
23
+ _MATPLIB_AVAILABLE = None
26
24
  __all__ = ("Graph",)
27
25
 
28
26
 
@@ -219,8 +217,17 @@ class Graph(Element, Relational, Generic[T]):
219
217
 
220
218
  def to_networkx(self, **kwargs) -> Any:
221
219
  """Convert the graph to a NetworkX graph object."""
220
+ global _NETWORKX_AVAILABLE
221
+ if _NETWORKX_AVAILABLE is None:
222
+ from lionagi.ln import is_import_installed
223
+
224
+ _NETWORKX_AVAILABLE = is_import_installed("networkx")
225
+
222
226
  if _NETWORKX_AVAILABLE is not True:
223
- raise _NETWORKX_AVAILABLE
227
+ raise ImportError(
228
+ "The 'networkx' package is required for this feature. "
229
+ "Please install `networkx` or `'lionagi[graph]'`."
230
+ )
224
231
 
225
232
  from networkx import DiGraph # type: ignore
226
233
 
@@ -248,8 +255,18 @@ class Graph(Element, Relational, Generic[T]):
248
255
  ):
249
256
  """Display the graph using NetworkX and Matplotlib."""
250
257
  g = self.to_networkx(**kwargs)
258
+
259
+ global _MATPLIB_AVAILABLE
260
+ if _MATPLIB_AVAILABLE is None:
261
+ from lionagi.ln import is_import_installed
262
+
263
+ _MATPLIB_AVAILABLE = is_import_installed("matplotlib")
264
+
251
265
  if _MATPLIB_AVAILABLE is not True:
252
- raise _MATPLIB_AVAILABLE
266
+ raise ImportError(
267
+ "The 'matplotlib' package is required for this feature. "
268
+ "Please install `matplotlib` or `'lionagi[graph]'`."
269
+ )
253
270
 
254
271
  import matplotlib.pyplot as plt # type: ignore
255
272
  import networkx as nx # type: ignore
@@ -62,6 +62,10 @@ class Node(Element, Relational, AsyncAdaptable, Adaptable):
62
62
  async def adapt_to_async(
63
63
  self, obj_key: str, many=False, **kwargs: Any
64
64
  ) -> Any:
65
+ # Only register postgres adapter if this specific operation needs it
66
+ if obj_key == "lionagi_async_pg":
67
+ _ensure_postgres_adapter()
68
+
65
69
  kwargs["adapt_meth"] = "to_dict"
66
70
  kwargs["adapt_kw"] = {"mode": "db"}
67
71
  return await super().adapt_to_async(
@@ -76,6 +80,10 @@ class Node(Element, Relational, AsyncAdaptable, Adaptable):
76
80
  many=False,
77
81
  **kwargs: Any,
78
82
  ) -> Node:
83
+ # Only register postgres adapter if this specific operation needs it
84
+ if obj_key == "lionagi_async_pg":
85
+ _ensure_postgres_adapter()
86
+
79
87
  kwargs["adapt_meth"] = "from_dict"
80
88
  return await super().adapt_from_async(
81
89
  obj, obj_key=obj_key, many=many, **kwargs
@@ -122,22 +130,31 @@ class Node(Element, Relational, AsyncAdaptable, Adaptable):
122
130
  return value
123
131
 
124
132
 
133
+ def _ensure_postgres_adapter():
134
+ """Lazy registration of postgres adapter when needed"""
135
+ if not hasattr(Node, "_postgres_adapter_checked"):
136
+ from lionagi.adapters._utils import check_async_postgres_available
137
+
138
+ if check_async_postgres_available() is True:
139
+ try:
140
+ from lionagi.adapters.async_postgres_adapter import (
141
+ LionAGIAsyncPostgresAdapter,
142
+ )
143
+
144
+ Node.register_async_adapter(LionAGIAsyncPostgresAdapter)
145
+ except ImportError:
146
+ pass # Graceful degradation if postgres dependencies missing
147
+ Node._postgres_adapter_checked = True
148
+
149
+
125
150
  if not _ADAPATER_REGISTERED:
126
151
  from pydapter.adapters import JsonAdapter, TomlAdapter
127
- from pydapter.extras.pandas_ import SeriesAdapter
128
152
 
129
153
  Node.register_adapter(JsonAdapter)
130
154
  Node.register_adapter(TomlAdapter)
131
- Node.register_adapter(SeriesAdapter)
132
-
133
- from lionagi.adapters._utils import check_async_postgres_available
134
-
135
- if check_async_postgres_available() is True:
136
- from lionagi.adapters.async_postgres_adapter import (
137
- LionAGIAsyncPostgresAdapter,
138
- )
139
155
 
140
- Node.register_async_adapter(LionAGIAsyncPostgresAdapter)
156
+ # PostgreSQL adapter registration is now lazy - only loaded when needed
157
+ # Call _ensure_postgres_adapter() in methods that actually use async adapters
141
158
 
142
159
  _ADAPATER_REGISTERED = True
143
160
 
@@ -4,7 +4,6 @@
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
- import json
8
7
  from pathlib import Path
9
8
  from typing import Any
10
9
 
@@ -5,10 +5,7 @@
5
5
  from ._concepts import Collective, Communicatable, Condition, Manager
6
6
  from ._concepts import Observable as LegacyObservable
7
7
  from ._concepts import Observer, Ordering, Relational, Sendable
8
- from .action.manager import ActionManager, FunctionCalling, Tool, ToolRef
9
8
  from .contracts import Observable, ObservableProto
10
- from .forms.flow import FlowDefinition, FlowStep
11
- from .forms.report import BaseForm, Form, Report
12
9
  from .generic.element import ID, Element, IDError, IDType, validate_order
13
10
  from .generic.event import Event, EventStatus, Execution
14
11
  from .generic.log import (
@@ -43,7 +40,6 @@ from .messages.manager import (
43
40
  SenderRecipient,
44
41
  System,
45
42
  )
46
- from .operatives.step import Operative, Step
47
43
 
48
44
  __all__ = (
49
45
  "Collective",
@@ -98,17 +94,6 @@ __all__ = (
98
94
  "RoledMessage",
99
95
  "SenderRecipient",
100
96
  "System",
101
- "FlowDefinition",
102
- "FlowStep",
103
- "BaseForm",
104
- "Form",
105
- "Report",
106
- "Operative",
107
- "Step",
108
- "ActionManager",
109
- "Tool",
110
- "FunctionCalling",
111
- "ToolRef",
112
97
  "MailManager",
113
98
  "DataLogger",
114
99
  "DataLoggerConfig",
@@ -1,10 +1,28 @@
1
+ # Eager imports for core functionality
1
2
  from .connections.api_calling import APICalling
2
3
  from .connections.endpoint import Endpoint, EndpointConfig
3
4
  from .hooks import *
4
5
  from .imodel import iModel
5
6
  from .manager import iModelManager
6
7
  from .rate_limited_processor import RateLimitedAPIExecutor
7
- from .token_calculator import TokenCalculator
8
+
9
+ # Lazy loading cache
10
+ _lazy_imports = {}
11
+
12
+
13
+ def __getattr__(name: str):
14
+ """Lazy loading for heavy service imports."""
15
+ if name in _lazy_imports:
16
+ return _lazy_imports[name]
17
+
18
+ if name == "TokenCalculator":
19
+ from .token_calculator import TokenCalculator
20
+
21
+ _lazy_imports["TokenCalculator"] = TokenCalculator
22
+ return TokenCalculator
23
+
24
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
25
+
8
26
 
9
27
  __all__ = (
10
28
  "APICalling",
@@ -12,10 +12,17 @@ from typing_extensions import Self
12
12
  from lionagi.protocols.generic.event import Event, EventStatus
13
13
  from lionagi.protocols.types import Log
14
14
  from lionagi.service.hooks import HookEvent, HookEventTypes, global_hook_logger
15
- from lionagi.service.token_calculator import TokenCalculator
16
15
 
17
16
  from .endpoint import Endpoint
18
17
 
18
+
19
+ # Lazy import for TokenCalculator
20
+ def _get_token_calculator():
21
+ from lionagi.service.token_calculator import TokenCalculator
22
+
23
+ return TokenCalculator
24
+
25
+
19
26
  logger = logging.getLogger(__name__)
20
27
 
21
28
 
@@ -129,7 +136,7 @@ class APICalling(Event):
129
136
 
130
137
  # Handle chat completions format
131
138
  if "messages" in self.payload:
132
- return TokenCalculator.calculate_message_tokens(
139
+ return _get_token_calculator().calculate_message_tokens(
133
140
  self.payload["messages"], **self.payload
134
141
  )
135
142
  # Handle responses API format
@@ -150,12 +157,14 @@ class APICalling(Event):
150
157
  messages.append(item)
151
158
  else:
152
159
  return None
153
- return TokenCalculator.calculate_message_tokens(
160
+ return _get_token_calculator().calculate_message_tokens(
154
161
  messages, **self.payload
155
162
  )
156
163
  # Handle embeddings endpoint
157
164
  elif "embed" in self.endpoint.config.endpoint:
158
- return TokenCalculator.calculate_embed_token(**self.payload)
165
+ return _get_token_calculator().calculate_embed_token(
166
+ **self.payload
167
+ )
159
168
 
160
169
  return None
161
170
 
@@ -5,18 +5,13 @@
5
5
  import asyncio
6
6
  import logging
7
7
 
8
- import aiohttp
9
- import backoff
10
- from aiocache import cached
11
8
  from pydantic import BaseModel
12
9
 
13
- from lionagi.config import settings
14
10
  from lionagi.service.resilience import (
15
11
  CircuitBreaker,
16
12
  RetryConfig,
17
13
  retry_with_backoff,
18
14
  )
19
- from lionagi.utils import to_dict
20
15
 
21
16
  from .endpoint_config import EndpointConfig
22
17
  from .header_factory import HeaderFactory
@@ -65,6 +60,8 @@ class Endpoint:
65
60
 
66
61
  def _create_http_session(self):
67
62
  """Create a new HTTP session (not thread-safe, create new for each request)."""
63
+ import aiohttp
64
+
68
65
  return aiohttp.ClientSession(
69
66
  timeout=aiohttp.ClientTimeout(self.config.timeout),
70
67
  **self.config.client_kwargs,
@@ -231,6 +228,9 @@ class Endpoint:
231
228
 
232
229
  # Handle caching if requested
233
230
  if cache_control:
231
+ from aiocache import cached
232
+
233
+ from lionagi.config import settings
234
234
 
235
235
  @cached(**settings.aiocache_config.as_kwargs())
236
236
  async def _cached_call(payload: dict, headers: dict, **kwargs):
@@ -268,6 +268,8 @@ class Endpoint:
268
268
  Returns:
269
269
  The response from the endpoint.
270
270
  """
271
+ import aiohttp
272
+ import backoff
271
273
 
272
274
  async def _make_request_with_backoff():
273
275
  # Create a new session for this request
@@ -382,6 +384,8 @@ class Endpoint:
382
384
  **kwargs,
383
385
  ) as response:
384
386
  if response.status != 200:
387
+ import aiohttp
388
+
385
389
  raise aiohttp.ClientResponseError(
386
390
  request_info=response.request_info,
387
391
  history=response.history,
@@ -409,6 +413,8 @@ class Endpoint:
409
413
 
410
414
  @classmethod
411
415
  def from_dict(cls, data: dict):
416
+ from lionagi.utils import to_dict
417
+
412
418
  data = to_dict(data, recursive=True)
413
419
  retry_config = data.get("retry_config")
414
420
  circuit_breaker = data.get("circuit_breaker")
lionagi/service/types.py CHANGED
@@ -2,6 +2,7 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
+ # Eager imports for core functionality
5
6
  from .connections.api_calling import APICalling
6
7
  from .connections.endpoint import Endpoint, EndpointConfig
7
8
  from .connections.providers.types import *
@@ -9,7 +10,24 @@ from .hooks import *
9
10
  from .imodel import iModel
10
11
  from .manager import iModelManager
11
12
  from .rate_limited_processor import RateLimitedAPIExecutor
12
- from .token_calculator import TokenCalculator
13
+
14
+ # Lazy loading cache
15
+ _lazy_imports = {}
16
+
17
+
18
+ def __getattr__(name: str):
19
+ """Lazy loading for heavy service imports."""
20
+ if name in _lazy_imports:
21
+ return _lazy_imports[name]
22
+
23
+ if name == "TokenCalculator":
24
+ from .token_calculator import TokenCalculator
25
+
26
+ _lazy_imports["TokenCalculator"] = TokenCalculator
27
+ return TokenCalculator
28
+
29
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
30
+
13
31
 
14
32
  __all__ = (
15
33
  "APICalling",
lionagi/session/branch.py CHANGED
@@ -4,10 +4,8 @@
4
4
 
5
5
  from collections.abc import AsyncGenerator, Callable
6
6
  from enum import Enum
7
- from typing import Any, Literal
7
+ from typing import TYPE_CHECKING, Any, Literal, Optional
8
8
 
9
- import pandas as pd
10
- from jinja2 import Template
11
9
  from pydantic import BaseModel, Field, JsonValue, PrivateAttr, field_serializer
12
10
 
13
11
  from lionagi.config import settings
@@ -15,11 +13,11 @@ from lionagi.fields import Instruct
15
13
  from lionagi.libs.schema.as_readable import as_readable
16
14
  from lionagi.models.field_model import FieldModel
17
15
  from lionagi.operations.manager import OperationManager
16
+ from lionagi.protocols.action.manager import ActionManager
18
17
  from lionagi.protocols.action.tool import FuncTool, Tool, ToolRef
19
18
  from lionagi.protocols.types import (
20
19
  ID,
21
20
  MESSAGE_FIELDS,
22
- ActionManager,
23
21
  ActionRequest,
24
22
  ActionResponse,
25
23
  AssistantResponse,
@@ -34,8 +32,6 @@ from lionagi.protocols.types import (
34
32
  Mailbox,
35
33
  MessageManager,
36
34
  MessageRole,
37
- Operative,
38
- Package,
39
35
  PackageCategory,
40
36
  Pile,
41
37
  Progression,
@@ -54,6 +50,10 @@ from lionagi.utils import copy
54
50
 
55
51
  from .prompts import LION_SYSTEM_MESSAGE
56
52
 
53
+ if TYPE_CHECKING:
54
+ from lionagi.protocols.operatives.operative import Operative
55
+
56
+
57
57
  __all__ = ("Branch",)
58
58
 
59
59
 
@@ -117,18 +117,18 @@ class Branch(Element, Communicatable, Relational):
117
117
  def __init__(
118
118
  self,
119
119
  *,
120
- user: SenderRecipient = None,
120
+ user: "SenderRecipient" = None,
121
121
  name: str | None = None,
122
122
  messages: Pile[RoledMessage] = None, # message manager kwargs
123
123
  system: System | JsonValue = None,
124
- system_sender: SenderRecipient = None,
124
+ system_sender: "SenderRecipient" = None,
125
125
  chat_model: iModel | dict = None, # iModelManager kwargs
126
126
  parse_model: iModel | dict = None,
127
127
  imodel: iModel = None, # deprecated, alias of chat_model
128
128
  tools: FuncTool | list[FuncTool] = None, # ActionManager kwargs
129
129
  log_config: LogManagerConfig | dict = None, # LogManager kwargs
130
130
  system_datetime: bool | str = None,
131
- system_template: Template | str = None,
131
+ system_template=None,
132
132
  system_template_context: dict = None,
133
133
  logs: Pile[Log] = None,
134
134
  use_lion_system_message: bool = False,
@@ -163,7 +163,7 @@ class Branch(Element, Communicatable, Relational):
163
163
  system_datetime (bool | str, optional):
164
164
  Whether to include timestamps in system messages (True/False)
165
165
  or a string format for datetime.
166
- system_template (Template | str, optional):
166
+ system_template (jinja2.Template | str, optional):
167
167
  Optional Jinja2 template for system messages.
168
168
  system_template_context (dict, optional):
169
169
  Context for rendering the system template.
@@ -177,6 +177,8 @@ class Branch(Element, Communicatable, Relational):
177
177
  super().__init__(user=user, name=name, **kwargs)
178
178
 
179
179
  # --- MessageManager ---
180
+ from lionagi.protocols.messages.manager import MessageManager
181
+
180
182
  self._message_manager = MessageManager(messages=messages)
181
183
 
182
184
  if any(
@@ -401,7 +403,7 @@ class Branch(Element, Communicatable, Relational):
401
403
  # -------------------------------------------------------------------------
402
404
  # Conversion / Serialization
403
405
  # -------------------------------------------------------------------------
404
- def to_df(self, *, progression: Progression = None) -> pd.DataFrame:
406
+ def to_df(self, *, progression: Progression = None):
405
407
  """
406
408
  Convert branch messages into a `pandas.DataFrame`.
407
409
 
@@ -412,6 +414,8 @@ class Branch(Element, Communicatable, Relational):
412
414
  Returns:
413
415
  pd.DataFrame: Each row represents a message, with columns defined by MESSAGE_FIELDS.
414
416
  """
417
+ from lionagi.protocols.generic.pile import Pile
418
+
415
419
  if progression is None:
416
420
  progression = self.msgs.progression
417
421
 
@@ -429,7 +433,7 @@ class Branch(Element, Communicatable, Relational):
429
433
  def send(
430
434
  self,
431
435
  recipient: IDType,
432
- category: PackageCategory | None,
436
+ category: Optional["PackageCategory"],
433
437
  item: Any,
434
438
  request_source: IDType | None = None,
435
439
  ) -> None:
@@ -446,6 +450,8 @@ class Branch(Element, Communicatable, Relational):
446
450
  request_source (IDType | None):
447
451
  The ID that prompted or requested this send operation (optional).
448
452
  """
453
+ from lionagi.protocols.mail.package import Package
454
+
449
455
  package = Package(
450
456
  category=category,
451
457
  item=item,
@@ -833,7 +839,7 @@ class Branch(Element, Communicatable, Relational):
833
839
  ] = "return_value",
834
840
  max_retries: int = 3,
835
841
  request_type: type[BaseModel] = None,
836
- operative: Operative = None,
842
+ operative: "Operative" = None,
837
843
  similarity_algo="jaro_winkler",
838
844
  similarity_threshold: float = 0.85,
839
845
  fuzzy_match: bool = True,
@@ -911,8 +917,8 @@ class Branch(Element, Communicatable, Relational):
911
917
  instruction: Instruction | JsonValue = None,
912
918
  guidance: JsonValue = None,
913
919
  context: JsonValue = None,
914
- sender: SenderRecipient = None,
915
- recipient: SenderRecipient = None,
920
+ sender: "SenderRecipient" = None,
921
+ recipient: "SenderRecipient" = None,
916
922
  progression: Progression = None,
917
923
  chat_model: iModel = None,
918
924
  invoke_actions: bool = True,
@@ -922,7 +928,7 @@ class Branch(Element, Communicatable, Relational):
922
928
  parse_model: iModel = None,
923
929
  skip_validation: bool = False,
924
930
  tools: ToolRef = None,
925
- operative: Operative = None,
931
+ operative: "Operative" = None,
926
932
  response_format: type[
927
933
  BaseModel
928
934
  ] = None, # alias of operative.request_type
@@ -1063,8 +1069,8 @@ class Branch(Element, Communicatable, Relational):
1063
1069
  guidance: JsonValue = None,
1064
1070
  context: JsonValue = None,
1065
1071
  plain_content: str = None,
1066
- sender: SenderRecipient = None,
1067
- recipient: SenderRecipient = None,
1072
+ sender: "SenderRecipient" = None,
1073
+ recipient: "SenderRecipient" = None,
1068
1074
  progression: ID.IDSeq = None,
1069
1075
  response_format: type[BaseModel] = None,
1070
1076
  request_fields: dict | list[str] = None,