lionagi 0.5.1__py3-none-any.whl → 0.5.3__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. lionagi/__init__.py +3 -1
  2. lionagi/core/action/tool.py +3 -5
  3. lionagi/core/communication/action_request.py +3 -3
  4. lionagi/core/communication/message.py +3 -3
  5. lionagi/core/communication/utils.py +3 -3
  6. lionagi/core/generic/component.py +4 -4
  7. lionagi/core/generic/element.py +51 -47
  8. lionagi/core/generic/graph.py +1 -1
  9. lionagi/core/generic/log.py +2 -2
  10. lionagi/core/generic/pile.py +10 -11
  11. lionagi/core/generic/progression.py +19 -12
  12. lionagi/core/generic/utils.py +6 -3
  13. lionagi/core/models/base.py +11 -68
  14. lionagi/core/models/field_model.py +42 -19
  15. lionagi/core/models/{new_model_params.py → model_params.py} +5 -6
  16. lionagi/core/models/note.py +2 -2
  17. lionagi/core/models/operable_model.py +8 -4
  18. lionagi/core/models/schema_model.py +9 -31
  19. lionagi/core/models/types.py +15 -6
  20. lionagi/core/session/branch.py +8 -4
  21. lionagi/core/session/branch_mixins.py +11 -12
  22. lionagi/core/session/session.py +1 -2
  23. lionagi/core/typing/__init__.py +4 -4
  24. lionagi/core/typing/{concepts.py → _concepts.py} +43 -2
  25. lionagi/core/typing/_id.py +104 -0
  26. lionagi/integrations/anthropic_/AnthropicModel.py +8 -3
  27. lionagi/integrations/groq_/GroqModel.py +11 -4
  28. lionagi/integrations/litellm_/imodel.py +6 -8
  29. lionagi/integrations/openai_/OpenAIModel.py +8 -3
  30. lionagi/integrations/openai_/image_token_calculator/image_token_calculator.py +14 -8
  31. lionagi/integrations/perplexity_/PerplexityModel.py +8 -3
  32. lionagi/libs/func/async_calls/__init__.py +6 -3
  33. lionagi/libs/func/async_calls/alcall.py +46 -0
  34. lionagi/libs/func/async_calls/bcall.py +49 -1
  35. lionagi/libs/func/async_calls/rcall.py +32 -0
  36. lionagi/libs/utils.py +12 -1
  37. lionagi/operations/brainstorm/brainstorm.py +4 -4
  38. lionagi/operations/brainstorm/prompt.py +8 -1
  39. lionagi/operations/plan/plan.py +3 -3
  40. lionagi/operations/plan/prompt.py +17 -16
  41. lionagi/protocols/__init__.py +3 -0
  42. lionagi/protocols/configs/__init__.py +0 -15
  43. lionagi/protocols/configs/branch_config.py +1 -1
  44. lionagi/protocols/configs/imodel_config.py +2 -2
  45. lionagi/protocols/configs/log_config.py +1 -1
  46. lionagi/protocols/configs/types.py +15 -0
  47. lionagi/protocols/operatives/__init__.py +3 -15
  48. lionagi/protocols/operatives/action.py +4 -0
  49. lionagi/protocols/operatives/instruct.py +6 -8
  50. lionagi/protocols/operatives/operative.py +9 -21
  51. lionagi/protocols/operatives/prompts.py +53 -202
  52. lionagi/protocols/operatives/reason.py +4 -0
  53. lionagi/protocols/operatives/step.py +11 -23
  54. lionagi/protocols/operatives/types.py +19 -0
  55. lionagi/protocols/registries/__init__.py +3 -0
  56. lionagi/protocols/registries/_component_registry.py +4 -0
  57. lionagi/protocols/registries/_pile_registry.py +4 -0
  58. lionagi/service/__init__.py +3 -0
  59. lionagi/service/service_match_util.py +4 -4
  60. lionagi/settings.py +10 -18
  61. lionagi/strategies/base.py +4 -5
  62. lionagi/strategies/concurrent.py +4 -3
  63. lionagi/strategies/concurrent_chunk.py +3 -3
  64. lionagi/strategies/concurrent_sequential_chunk.py +3 -3
  65. lionagi/strategies/params.py +7 -4
  66. lionagi/version.py +1 -1
  67. {lionagi-0.5.1.dist-info → lionagi-0.5.3.dist-info}/METADATA +5 -3
  68. {lionagi-0.5.1.dist-info → lionagi-0.5.3.dist-info}/RECORD +73 -72
  69. lionagi/core/typing/config.py +0 -15
  70. lionagi/core/typing/id.py +0 -221
  71. /lionagi/core/typing/{pydantic_.py → _pydantic.py} +0 -0
  72. /lionagi/core/typing/{typing_.py → _typing.py} +0 -0
  73. /lionagi/integrations/{services.py → _services.py} +0 -0
  74. {lionagi-0.5.1.dist-info → lionagi-0.5.3.dist-info}/WHEEL +0 -0
  75. {lionagi-0.5.1.dist-info → lionagi-0.5.3.dist-info}/licenses/LICENSE +0 -0
@@ -2,9 +2,13 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
- from ..typing.pydantic_ import ConfigDict, Field, FieldInfo, field_validator
6
- from ..typing.typing_ import UNDEFINED, Any, Callable
7
- from .schema_model import SchemaModel, common_config
5
+ from lionagi.libs.utils import is_same_dtype
6
+
7
+ from ..typing._pydantic import ConfigDict, Field, FieldInfo, field_validator
8
+ from ..typing._typing import UNDEFINED, Any, Callable, UndefinedType
9
+ from .schema_model import SchemaModel
10
+
11
+ __all__ = ("FieldModel",)
8
12
 
9
13
 
10
14
  class FieldModel(SchemaModel):
@@ -51,24 +55,34 @@ class FieldModel(SchemaModel):
51
55
  """
52
56
 
53
57
  model_config = ConfigDict(
54
- extra="allow", validate_default=False, **common_config
58
+ extra="allow",
59
+ validate_default=False,
60
+ populate_by_name=True,
61
+ arbitrary_types_allowed=True,
62
+ use_enum_values=True,
55
63
  )
56
64
 
57
65
  # Field configuration attributes
58
66
  default: Any = UNDEFINED # Default value
59
- default_factory: Callable = UNDEFINED # Factory function for default value
60
- title: str = UNDEFINED # Field title
61
- description: str = UNDEFINED # Field description
62
- examples: list = UNDEFINED # Example values
63
- validators: list = UNDEFINED # Validation functions
64
- exclude: bool = UNDEFINED # Exclude from serialization
65
- deprecated: bool = UNDEFINED # Mark as deprecated
66
- frozen: bool = UNDEFINED # Mark as immutable
67
- alias: str = UNDEFINED # Alternative field name
68
- alias_priority: int = UNDEFINED # Priority for alias resolution
67
+ default_factory: Callable | UndefinedType = (
68
+ UNDEFINED # Factory function for default value
69
+ )
70
+ title: str | UndefinedType = UNDEFINED # Field title
71
+ description: str | UndefinedType = UNDEFINED # Field description
72
+ examples: list | UndefinedType = UNDEFINED # Example values
73
+ validators: list | UndefinedType = UNDEFINED # Validation functions
74
+ exclude: bool | UndefinedType = UNDEFINED # Exclude from serialization
75
+ deprecated: bool | UndefinedType = UNDEFINED # Mark as deprecated
76
+ frozen: bool | UndefinedType = UNDEFINED # Mark as immutable
77
+ alias: str | UndefinedType = UNDEFINED # Alternative field name
78
+ alias_priority: int | UndefinedType = (
79
+ UNDEFINED # Priority for alias resolution
80
+ )
69
81
 
70
82
  # Core field attributes
71
- name: str = Field(..., exclude=True) # Field name (required)
83
+ name: str | UndefinedType = Field(
84
+ ..., exclude=True
85
+ ) # Field name (required)
72
86
  annotation: type | Any = Field(UNDEFINED, exclude=True) # Type annotation
73
87
  validator: Callable | Any = Field(
74
88
  UNDEFINED, exclude=True
@@ -77,6 +91,18 @@ class FieldModel(SchemaModel):
77
91
  default_factory=dict, exclude=True
78
92
  ) # Validator parameters
79
93
 
94
+ @field_validator("validators", mode="before")
95
+ def _validate_validators(cls, v) -> list[Callable]:
96
+ if v is None or v is UNDEFINED:
97
+ return []
98
+ if isinstance(v, Callable):
99
+ return [v]
100
+ if isinstance(v, list) and is_same_dtype(v, Callable):
101
+ return v
102
+ raise ValueError(
103
+ "Validators must be a list of functions or a function"
104
+ )
105
+
80
106
  @property
81
107
  def field_info(self) -> FieldInfo:
82
108
  """Generate Pydantic FieldInfo object from field configuration.
@@ -92,7 +118,7 @@ class FieldModel(SchemaModel):
92
118
  annotation = (
93
119
  self.annotation if self.annotation is not UNDEFINED else Any
94
120
  )
95
- field_obj: FieldInfo = Field(**self.to_dict(True)) # type: ignore
121
+ field_obj: FieldInfo = Field(**self.to_dict()) # type: ignore
96
122
  field_obj.annotation = annotation
97
123
  return field_obj
98
124
 
@@ -117,6 +143,3 @@ class FieldModel(SchemaModel):
117
143
  self.validator
118
144
  )
119
145
  }
120
-
121
-
122
- __all__ = ["FieldModel"]
@@ -9,7 +9,7 @@ from pydantic import BaseModel
9
9
  from lionagi.libs.parse import validate_boolean
10
10
  from lionagi.libs.utils import copy
11
11
 
12
- from ..typing.pydantic_ import (
12
+ from ..typing._pydantic import (
13
13
  Field,
14
14
  FieldInfo,
15
15
  PrivateAttr,
@@ -17,12 +17,14 @@ from ..typing.pydantic_ import (
17
17
  field_validator,
18
18
  model_validator,
19
19
  )
20
- from ..typing.typing_ import Callable, Self
20
+ from ..typing._typing import Callable, Self
21
21
  from .field_model import FieldModel
22
22
  from .schema_model import SchemaModel
23
23
 
24
+ __all__ = ("ModelParams",)
24
25
 
25
- class NewModelParams(SchemaModel):
26
+
27
+ class ModelParams(SchemaModel):
26
28
  """Configuration class for dynamically creating new Pydantic models."""
27
29
 
28
30
  name: str | None = None
@@ -190,6 +192,3 @@ class NewModelParams(SchemaModel):
190
192
  if self.frozen:
191
193
  a.model_config["frozen"] = True
192
194
  return a
193
-
194
-
195
- __all__ = ["NewModelParams"]
@@ -5,8 +5,8 @@
5
5
  from lionagi.libs.parse import flatten, nget, ninsert, npop, nset, to_list
6
6
  from lionagi.libs.utils import copy
7
7
 
8
- from ..typing.pydantic_ import ConfigDict, Field, field_serializer
9
- from ..typing.typing_ import (
8
+ from ..typing._pydantic import ConfigDict, Field, field_serializer
9
+ from ..typing._typing import (
10
10
  UNDEFINED,
11
11
  Any,
12
12
  ItemsView,
@@ -4,7 +4,7 @@
4
4
 
5
5
  from lionagi.libs.utils import is_same_dtype
6
6
 
7
- from ..typing.pydantic_ import (
7
+ from ..typing._pydantic import (
8
8
  ConfigDict,
9
9
  Field,
10
10
  FieldInfo,
@@ -12,8 +12,8 @@ from ..typing.pydantic_ import (
12
12
  field_serializer,
13
13
  field_validator,
14
14
  )
15
- from ..typing.typing_ import UNDEFINED, Any, TypeVar, override
16
- from .base import BaseAutoModel, common_config
15
+ from ..typing._typing import UNDEFINED, Any, TypeVar, override
16
+ from .base import BaseAutoModel
17
17
  from .field_model import FieldModel
18
18
 
19
19
  FIELD_NAME = TypeVar("FIELD_NAME", bound=str)
@@ -55,7 +55,11 @@ class OperableModel(BaseAutoModel):
55
55
  """
56
56
 
57
57
  model_config = ConfigDict(
58
- extra="forbid", validate_default=False, **common_config
58
+ extra="forbid",
59
+ validate_default=False,
60
+ populate_by_name=True,
61
+ arbitrary_types_allowed=True,
62
+ use_enum_values=True,
59
63
  )
60
64
 
61
65
  extra_fields: dict[str, Any] = Field(default_factory=dict)
@@ -2,39 +2,20 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
- from ..typing.pydantic_ import ConfigDict
6
- from .base import BaseAutoModel, common_config
5
+ from ..typing._pydantic import ConfigDict
6
+ from .base import BaseAutoModel
7
7
 
8
+ __all__ = ("SchemaModel",)
8
9
 
9
- class SchemaModel(BaseAutoModel):
10
- """Schema definition model with strict validation.
11
-
12
- Extends BaseAutoModel to provide:
13
- - Extra field forbidding
14
- - Disabled default validation
15
- - Field name listing
16
- - Nested validation
17
-
18
- Example:
19
- ```python
20
- class UserSchema(SchemaModel):
21
- name: str = Field(min_length=2)
22
- age: int = Field(gt=0)
23
- settings: dict[str, Any] = Field(default_factory=dict)
24
-
25
- # Raises error - extra fields forbidden
26
- user = UserSchema(name="John", age=30, extra="value")
27
- ```
28
10
 
29
- Attributes:
30
- model_config: Schema-specific configuration
31
- - extra: "forbid" to prevent extra fields
32
- - validate_default: False to skip default validation
33
- - Plus inherited BaseAutoModel config
34
- """
11
+ class SchemaModel(BaseAutoModel):
35
12
 
36
13
  model_config = ConfigDict(
37
- extra="forbid", validate_default=False, **common_config
14
+ extra="forbid",
15
+ validate_default=False,
16
+ populate_by_name=True,
17
+ arbitrary_types_allowed=True,
18
+ use_enum_values=True,
38
19
  )
39
20
 
40
21
  @classmethod
@@ -45,6 +26,3 @@ class SchemaModel(BaseAutoModel):
45
26
  List of field names defined in model schema
46
27
  """
47
28
  return list(cls.model_fields.keys())
48
-
49
-
50
- __all__ = ["SchemaModel"]
@@ -2,9 +2,18 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
- from .base import *
6
- from .field_model import *
7
- from .new_model_params import *
8
- from .note import *
9
- from .operable_model import *
10
- from .schema_model import *
5
+ from .base import BaseAutoModel
6
+ from .field_model import FieldModel
7
+ from .model_params import ModelParams
8
+ from .note import Note
9
+ from .operable_model import OperableModel
10
+ from .schema_model import SchemaModel
11
+
12
+ __all__ = (
13
+ "BaseAutoModel",
14
+ "FieldModel",
15
+ "ModelParams",
16
+ "Note",
17
+ "OperableModel",
18
+ "SchemaModel",
19
+ )
@@ -42,29 +42,33 @@ class Branch(Component, BranchActionMixin, BranchOperationMixin):
42
42
  )
43
43
  if not message_manager.logger:
44
44
  message_manager.logger = LogManager(
45
- **Settings.Branch.BRANCH.message_log_config.to_dict(True)
45
+ **Settings.Branch.BRANCH.message_log_config.to_dict()
46
46
  )
47
47
 
48
48
  acts = data.pop("acts", None)
49
49
  if not acts:
50
50
  acts = ActionManager()
51
51
  acts.logger = LogManager(
52
- **Settings.Branch.BRANCH.action_log_config.to_dict(True)
52
+ **Settings.Branch.BRANCH.action_log_config.to_dict()
53
53
  )
54
54
  if "tools" in data:
55
55
  acts.register_tools(data.pop("tools"))
56
56
 
57
57
  imodel = data.pop(
58
58
  "imodel",
59
- LiteiModel(**Settings.iModel.CHAT),
59
+ iModel(**Settings.iModel.CHAT.to_dict()),
60
+ )
61
+ parse_imodel = data.pop(
62
+ "parse_imodel",
63
+ iModel(**Settings.iModel.PARSE.to_dict()),
60
64
  )
61
-
62
65
  out = {
63
66
  "user": user,
64
67
  "name": name,
65
68
  "msgs": message_manager,
66
69
  "acts": acts,
67
70
  "imodel": imodel,
71
+ "parse_imodel": parse_imodel,
68
72
  **data,
69
73
  }
70
74
  return out
@@ -14,13 +14,12 @@ from lionagi.core.typing import (
14
14
  UNDEFINED,
15
15
  BaseModel,
16
16
  FieldModel,
17
- NewModelParams,
17
+ ModelParams,
18
18
  )
19
- from lionagi.integrations.litellm_.imodel import LiteiModel
20
19
  from lionagi.integrations.pydantic_ import break_down_pydantic_annotation
21
20
  from lionagi.libs.func.types import alcall
22
21
  from lionagi.libs.parse import to_json, validate_mapping
23
- from lionagi.protocols.operatives import (
22
+ from lionagi.protocols.operatives.types import (
24
23
  ActionRequestModel,
25
24
  ActionResponseModel,
26
25
  Operative,
@@ -108,7 +107,7 @@ class BranchOperationMixin(ABC):
108
107
  recipient=None,
109
108
  operative_model: type[BaseModel] = None,
110
109
  progress=None,
111
- imodel: iModel | LiteiModel = None,
110
+ imodel: iModel = None,
112
111
  reason: bool = False,
113
112
  actions: bool = False,
114
113
  exclude_fields: list | dict | None = None,
@@ -120,15 +119,15 @@ class BranchOperationMixin(ABC):
120
119
  images: list = None,
121
120
  image_detail: Literal["low", "high", "auto"] = None,
122
121
  max_retries: int = None,
123
- retry_imodel: iModel | LiteiModel = None,
122
+ retry_imodel: iModel = None,
124
123
  retry_kwargs: dict = {},
125
124
  auto_retry_parse: bool = True,
126
125
  field_models: list[FieldModel] | None = None,
127
126
  skip_validation: bool = False,
128
127
  tools: str | Tool | list[Tool | str] | bool = None,
129
- request_params: NewModelParams = None,
128
+ request_params: ModelParams = None,
130
129
  request_param_kwargs: dict = {},
131
- response_params: NewModelParams = None,
130
+ response_params: ModelParams = None,
132
131
  response_param_kwargs: dict = {},
133
132
  **kwargs,
134
133
  ) -> list | BaseModel | None | dict | str:
@@ -269,7 +268,7 @@ class BranchOperationMixin(ABC):
269
268
  request_fields=None,
270
269
  request_model: type[BaseModel] = None,
271
270
  progress=None,
272
- imodel: iModel | LiteiModel = None,
271
+ imodel: iModel = None,
273
272
  tool_schemas=None,
274
273
  images: list = None,
275
274
  image_detail: Literal["low", "high", "auto"] = None,
@@ -321,9 +320,9 @@ class BranchOperationMixin(ABC):
321
320
  imodel = imodel or self.imodel
322
321
  api_response = None
323
322
 
324
- if isinstance(imodel, LiteiModel):
323
+ if not hasattr(imodel, "parse_to_data_model"):
325
324
  api_response = await imodel.invoke(**kwargs)
326
- elif isinstance(imodel, iModel):
325
+ else:
327
326
  data_model = imodel.parse_to_data_model(**kwargs)
328
327
  api_response = await imodel.invoke(**data_model)
329
328
 
@@ -344,12 +343,12 @@ class BranchOperationMixin(ABC):
344
343
  progress: ID.IDSeq = None,
345
344
  request_model: type[BaseModel] | BaseModel = None,
346
345
  request_fields: dict | list[str] = None,
347
- imodel: iModel | LiteiModel = None,
346
+ imodel: iModel = None,
348
347
  images: list = None,
349
348
  image_detail: Literal["low", "high", "auto"] = None,
350
349
  tools: str | FUNCTOOL | list[FUNCTOOL | str] | bool = None,
351
350
  num_parse_retries: int = 0,
352
- retry_imodel: iModel | LiteiModel = None,
351
+ retry_imodel: iModel = None,
353
352
  retry_kwargs: dict = {},
354
353
  handle_validation: Literal[
355
354
  "raise", "return_value", "return_none"
@@ -8,7 +8,6 @@ import pandas as pd
8
8
 
9
9
  from lionagi.core.generic.types import Component, Pile, Progression
10
10
  from lionagi.core.typing import ID, Field, ItemNotFoundError, JsonValue
11
- from lionagi.integrations.litellm_.imodel import LiteiModel
12
11
  from lionagi.libs.parse import to_list
13
12
  from lionagi.service import iModel
14
13
 
@@ -39,7 +38,7 @@ class Session(Component):
39
38
  system_datetime: bool | str = None,
40
39
  user: ID.SenderRecipient = None,
41
40
  name: str | None = None,
42
- imodel: iModel | LiteiModel | None = None,
41
+ imodel: iModel | None = None,
43
42
  messages: Pile[RoledMessage] = None,
44
43
  progress: Progression = None,
45
44
  tool_manager: ActionManager = None,
@@ -3,7 +3,7 @@
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
5
  from ..models import *
6
- from .concepts import *
7
- from .id import *
8
- from .pydantic_ import *
9
- from .typing_ import *
6
+ from ._concepts import *
7
+ from ._id import *
8
+ from ._pydantic import *
9
+ from ._typing import *
@@ -2,19 +2,59 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
+ from __future__ import annotations
6
+
7
+ import uuid
5
8
  from abc import ABC, abstractmethod
9
+ from dataclasses import dataclass
6
10
  from typing import Any, Generic, TypeVar
7
11
 
12
+ from lionagi.settings import Settings
13
+
14
+
15
+ class IDType:
16
+
17
+ def __init__(self, _id: uuid.UUID):
18
+ self._id = _id
19
+
20
+ @classmethod
21
+ def validate(cls, value) -> IDType:
22
+ if isinstance(value, cls):
23
+ return value
24
+ if isinstance(value, str | int):
25
+ try:
26
+ _id = uuid.UUID(value, version=Settings.Config.UUID_VERSION)
27
+ return cls(_id=_id)
28
+ except Exception as e:
29
+ raise ValueError(f"Invalid IDType value: {value}") from e
30
+ raise ValueError(f"Invalid IDType value: {value}")
31
+
32
+ def __str__(self):
33
+ return str(self._id)
34
+
35
+ def __repr__(self):
36
+ return f"{self.__class__.__name__}({self._id})"
37
+
38
+ def __hash__(self):
39
+ return hash(self._id)
40
+
41
+ def __eq__(self, other):
42
+ if not isinstance(other, IDType):
43
+ return False
44
+ return self._id == other._id
45
+
46
+ __slots__ = ("_id",)
47
+
8
48
 
9
49
  class Observable(ABC):
10
50
  """
11
51
  Abstract base class for objects that can be uniquely identified and tracked.
12
52
 
13
- All Observable objects must have a unique identifier (ln_id) that allows them
53
+ All Observable objects must have a unique identifier (id) that allows them
14
54
  to be tracked and referenced within the Lion system.
15
55
  """
16
56
 
17
- ln_id: str
57
+ ln_id: IDType
18
58
 
19
59
 
20
60
  T = TypeVar("T", bound=Observable)
@@ -129,4 +169,5 @@ __all__ = [
129
169
  "Condition",
130
170
  "Structure",
131
171
  "RelationError",
172
+ "IDType",
132
173
  ]
@@ -0,0 +1,104 @@
1
+ # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from __future__ import annotations
6
+
7
+ import uuid
8
+
9
+ from lionagi.settings import Settings
10
+
11
+ from ._concepts import (
12
+ Container,
13
+ Generic,
14
+ IDType,
15
+ ItemError,
16
+ Observable,
17
+ Ordering,
18
+ T,
19
+ )
20
+ from ._typing import Container, Mapping, Sequence, TypeAlias
21
+
22
+
23
+ class IDError(ItemError):
24
+ """Exception raised when an item does not have a Lion ID."""
25
+
26
+ def __init__(
27
+ self,
28
+ message: str = "Item must contain a Lion ID.",
29
+ item_id: str | None = None,
30
+ ):
31
+ super().__init__(message, item_id)
32
+
33
+
34
+ class ID(Generic[T]):
35
+ """
36
+ A generic class that provides ID-related functionality for Observable objects.
37
+
38
+ This class handles the generation, validation, and management of unique identifiers
39
+ within the Lion system. It provides type aliases for various ID-related operations
40
+ and methods for working with IDs.
41
+ """
42
+
43
+ # For functions that accept either ID or item
44
+ Ref: TypeAlias = IDType | T # type: ignore
45
+
46
+ # For functions requiring just the ID
47
+ ID: TypeAlias = IDType
48
+
49
+ # For functions requiring Observable object
50
+ Item = T # type: ignore
51
+
52
+ # For collections
53
+ IDSeq: TypeAlias = list[IDType] | Ordering
54
+ ItemSeq: TypeAlias = ( # type: ignore
55
+ Sequence[T] | Mapping[IDType, T] | Container[IDType | T]
56
+ )
57
+ RefSeq: TypeAlias = IDSeq | ItemSeq
58
+
59
+ # For system-level interactions
60
+ SenderRecipient: TypeAlias = IDType | T | str # type: ignore
61
+
62
+ @staticmethod
63
+ def id():
64
+ return IDType(
65
+ _id=getattr(uuid, f"uuid{Settings.Config.UUID_VERSION}")()
66
+ )
67
+
68
+ @staticmethod
69
+ def get_id(item, /) -> IDType:
70
+
71
+ if isinstance(item, Observable):
72
+ return item.ln_id
73
+ try:
74
+ return IDType.validate(item)
75
+ except ValueError as e:
76
+ raise IDError(
77
+ f"The input object of type <{type(item).__name__}> does "
78
+ "not contain or is not a valid Lion ID. Item must be an instance"
79
+ " of `Observable` or a valid `id`."
80
+ ) from e
81
+
82
+ @staticmethod
83
+ def is_id(item, /) -> bool:
84
+ """
85
+ Check if an item is or contains a valid Lion ID.
86
+
87
+ Args:
88
+ item: The item to check.
89
+ config: Configuration dictionary for ID validation.
90
+
91
+ Returns:
92
+ True if the item is a valid Lion ID, False otherwise.
93
+ """
94
+ try:
95
+ ID.get_id(item)
96
+ return True
97
+ except IDError:
98
+ return False
99
+
100
+
101
+ __all__ = [
102
+ "ID",
103
+ "IDError",
104
+ ]
@@ -4,7 +4,6 @@
4
4
 
5
5
  from pathlib import Path
6
6
 
7
- import yaml
8
7
  from dotenv import load_dotenv
9
8
  from pydantic import (
10
9
  BaseModel,
@@ -34,6 +33,12 @@ price_config_file_name = path / "anthropic_price_data.yaml"
34
33
  max_output_token_file_name = path / "anthropic_max_output_token_data.yaml"
35
34
 
36
35
 
36
+ class _ModuleImportClass:
37
+ from lionagi.libs.package.imports import check_import
38
+
39
+ yaml = check_import("yaml", pip_name="pyyaml")
40
+
41
+
37
42
  class AnthropicModel(BaseModel):
38
43
  model: str = Field(description="ID of the model to use.")
39
44
 
@@ -234,7 +239,7 @@ class AnthropicModel(BaseModel):
234
239
  )
235
240
  if estimated_output_len == 0:
236
241
  with open(max_output_token_file_name) as file:
237
- output_token_config = yaml.safe_load(file)
242
+ output_token_config = _ModuleImportClass.yaml.safe_load(file)
238
243
  estimated_output_len = output_token_config.get(self.model, 0)
239
244
  self.estimated_output_len = estimated_output_len
240
245
 
@@ -256,7 +261,7 @@ class AnthropicModel(BaseModel):
256
261
  num_of_input_tokens = self.text_token_calculator.calculate(input_text)
257
262
 
258
263
  with open(price_config_file_name) as file:
259
- price_config = yaml.safe_load(file)
264
+ price_config = _ModuleImportClass.yaml.safe_load(file)
260
265
 
261
266
  model_price_info_dict = price_config["model"][self.model]
262
267
  estimated_price = (
@@ -5,7 +5,6 @@
5
5
  import warnings
6
6
  from pathlib import Path
7
7
 
8
- import yaml
9
8
  from dotenv import load_dotenv
10
9
  from pydantic import (
11
10
  BaseModel,
@@ -34,6 +33,12 @@ max_output_token_file_name = path / "groq_max_output_token_data.yaml"
34
33
  rate_limits_file_name = path / "groq_rate_limits.yaml"
35
34
 
36
35
 
36
+ class _ModuleImportClass:
37
+ from lionagi.libs.package.imports import check_import
38
+
39
+ yaml = check_import("yaml", pip_name="pyyaml")
40
+
41
+
37
42
  class GroqModel(BaseModel):
38
43
  model: str = Field(description="ID of the model to use.")
39
44
  request_model: GroqRequest = Field(description="Making requests")
@@ -67,7 +72,7 @@ class GroqModel(BaseModel):
67
72
  # Load rate limits from YAML
68
73
  try:
69
74
  with open(rate_limits_file_name) as file:
70
- rate_limits = yaml.safe_load(file)
75
+ rate_limits = _ModuleImportClass.yaml.safe_load(file)
71
76
  model_name = data.get("model")
72
77
  model_limits = None
73
78
 
@@ -261,7 +266,9 @@ class GroqModel(BaseModel):
261
266
  if estimated_output_len == 0:
262
267
  try:
263
268
  with open(max_output_token_file_name) as file:
264
- output_token_config = yaml.safe_load(file)
269
+ output_token_config = _ModuleImportClass.yaml.safe_load(
270
+ file
271
+ )
265
272
  estimated_output_len = output_token_config.get(
266
273
  self.model, 2048
267
274
  ) # Default to 2048
@@ -297,7 +304,7 @@ class GroqModel(BaseModel):
297
304
 
298
305
  try:
299
306
  with open(price_config_file_name) as file:
300
- price_config = yaml.safe_load(file)
307
+ price_config = _ModuleImportClass.yaml.safe_load(file)
301
308
  except FileNotFoundError:
302
309
  raise ValueError(
303
310
  f"Price config file not found: {price_config_file_name}"