lionagi 0.3.6__py3-none-any.whl → 0.3.8__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,11 +1,11 @@
1
1
  """Component class, base building block in LionAGI."""
2
2
 
3
3
  import contextlib
4
- from abc import ABC
5
- from collections.abc import Sequence
6
4
  from functools import singledispatchmethod
7
- from typing import Any, Type, TypeAlias, TypeVar, Union
5
+ from typing import Any, TypeAlias, TypeVar, Union
8
6
 
7
+ import lionfuncs as ln
8
+ from lionabc import Observable
9
9
  from pandas import DataFrame, Series
10
10
  from pydantic import AliasChoices, BaseModel, Field, ValidationError
11
11
 
@@ -22,7 +22,13 @@ T = TypeVar("T")
22
22
  _init_class = {}
23
23
 
24
24
 
25
- class Element(BaseModel, ABC):
25
+ def change_dict_key(dict_: dict, old_key: str, new_key: str) -> None:
26
+ """Change a key in a dictionary."""
27
+ if old_key in dict_:
28
+ dict_[new_key] = dict_.pop(old_key)
29
+
30
+
31
+ class Element(BaseModel, Observable):
26
32
  """Base class for elements within the LionAGI system.
27
33
 
28
34
  Attributes:
@@ -31,15 +37,14 @@ class Element(BaseModel, ABC):
31
37
  """
32
38
 
33
39
  ln_id: str = Field(
34
- default_factory=SysUtil.create_id,
40
+ default_factory=SysUtil.id,
35
41
  title="ID",
36
- description="A 32-char unique hash identifier.",
37
42
  frozen=True,
38
43
  validation_alias=AliasChoices("node_id", "ID", "id"),
39
44
  )
40
45
 
41
46
  timestamp: str = Field(
42
- default_factory=lambda: SysUtil.get_timestamp(sep=None)[:-6],
47
+ default_factory=lambda: ln.time(type_="iso"),
43
48
  title="Creation Timestamp",
44
49
  description="The UTC timestamp of creation",
45
50
  frozen=True,
@@ -57,7 +62,7 @@ class Element(BaseModel, ABC):
57
62
  return True
58
63
 
59
64
 
60
- class Component(Element, ABC):
65
+ class Component(Element):
61
66
  """
62
67
  Represents a distinguishable, temporal entity in LionAGI.
63
68
 
@@ -195,17 +200,15 @@ class Component(Element, ABC):
195
200
  """Create a Component instance from a LlamaIndex object."""
196
201
  dict_ = obj.to_dict()
197
202
 
198
- SysUtil.change_dict_key(dict_, "text", "content")
203
+ change_dict_key(dict_, "text", "content")
199
204
  metadata = dict_.pop("metadata", {})
200
205
 
201
206
  for field in llama_meta_fields:
202
207
  metadata[field] = dict_.pop(field, None)
203
208
 
204
- SysUtil.change_dict_key(metadata, "class_name", "llama_index_class")
205
- SysUtil.change_dict_key(metadata, "id_", "llama_index_id")
206
- SysUtil.change_dict_key(
207
- metadata, "relationships", "llama_index_relationships"
208
- )
209
+ change_dict_key(metadata, "class_name", "llama_index_class")
210
+ change_dict_key(metadata, "id_", "llama_index_id")
211
+ change_dict_key(metadata, "relationships", "llama_index_relationships")
209
212
 
210
213
  dict_["metadata"] = metadata
211
214
  return cls.from_obj(dict_)
@@ -244,7 +247,7 @@ class Component(Element, ABC):
244
247
  @classmethod
245
248
  def _process_langchain_dict(cls, dict_: dict) -> dict:
246
249
  """Process a dictionary containing Langchain-specific data."""
247
- SysUtil.change_dict_key(dict_, "page_content", "content")
250
+ change_dict_key(dict_, "page_content", "content")
248
251
 
249
252
  metadata = dict_.pop("metadata", {})
250
253
  metadata.update(dict_.pop("kwargs", {}))
@@ -264,9 +267,9 @@ class Component(Element, ABC):
264
267
  if field in dict_:
265
268
  metadata[field] = dict_.pop(field)
266
269
 
267
- SysUtil.change_dict_key(metadata, "lc", "langchain")
268
- SysUtil.change_dict_key(metadata, "type", "lc_type")
269
- SysUtil.change_dict_key(metadata, "id", "lc_id")
270
+ change_dict_key(metadata, "lc", "langchain")
271
+ change_dict_key(metadata, "type", "lc_type")
272
+ change_dict_key(metadata, "id", "lc_id")
270
273
 
271
274
  extra_fields = {
272
275
  k: v for k, v in metadata.items() if k not in lc_meta_fields
@@ -298,9 +301,9 @@ class Component(Element, ABC):
298
301
  dict_["metadata"] = meta_
299
302
 
300
303
  if "ln_id" not in dict_:
301
- dict_["ln_id"] = meta_.pop("ln_id", SysUtil.create_id())
304
+ dict_["ln_id"] = meta_.pop("ln_id", SysUtil.id())
302
305
  if "timestamp" not in dict_:
303
- dict_["timestamp"] = SysUtil.get_timestamp(sep=None)[:-6]
306
+ dict_["timestamp"] = ln.time(type_="iso")
304
307
  if "metadata" not in dict_:
305
308
  dict_["metadata"] = {}
306
309
  if "extra_fields" not in dict_:
@@ -453,13 +456,13 @@ class Component(Element, ABC):
453
456
  ninsert(
454
457
  self.metadata,
455
458
  ["last_updated", name],
456
- SysUtil.get_timestamp(sep=None)[:-6],
459
+ ln.time(type_="iso")[:-6],
457
460
  )
458
461
  elif isinstance(a, tuple) and isinstance(a[0], int):
459
462
  nset(
460
463
  self.metadata,
461
464
  ["last_updated", name],
462
- SysUtil.get_timestamp(sep=None)[:-6],
465
+ ln.time(type_="iso")[:-6],
463
466
  )
464
467
 
465
468
  def _meta_pop(self, indices, default=...):
@@ -614,10 +617,4 @@ LionIDable: TypeAlias = Union[str, Element]
614
617
 
615
618
  def get_lion_id(item: LionIDable) -> str:
616
619
  """Get the Lion ID of an item."""
617
- if isinstance(item, Sequence) and len(item) == 1:
618
- item = item[0]
619
- if isinstance(item, str) and len(item) == 32:
620
- return item
621
- if getattr(item, "ln_id", None) is not None:
622
- return item.ln_id
623
- raise LionTypeError("Item must be a single LionIDable object.")
620
+ return SysUtil.get_id(item)
@@ -227,12 +227,6 @@ class Sendable(BaseModel, ABC):
227
227
  return value
228
228
 
229
229
  a = get_lion_id(value)
230
- if not isinstance(a, str) or len(a) != 32:
231
- raise LionTypeError(
232
- "Invalid sender or recipient value. "
233
- "Expected a valid node id or one of "
234
- "'system' or 'user'."
235
- )
236
230
  return a
237
231
 
238
232
 
@@ -1,7 +1,6 @@
1
1
  import contextlib
2
2
  from collections import deque
3
3
  from collections.abc import Mapping
4
- from typing import Tuple
5
4
 
6
5
  from pydantic import Field
7
6
 
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  import os
3
3
 
4
+ import lionfuncs as ln
4
5
  import numpy as np
5
6
  from dotenv import load_dotenv
6
7
 
@@ -91,8 +92,8 @@ class iModel:
91
92
  service (BaseService, optional): An instance of BaseService.
92
93
  **kwargs: Additional parameters for the model.
93
94
  """
94
- self.ln_id: str = SysUtil.create_id()
95
- self.timestamp: str = SysUtil.get_timestamp(sep=None)[:-6]
95
+ self.ln_id: str = SysUtil.id()
96
+ self.timestamp: str = ln.time(type_="iso")
96
97
  self.endpoint = endpoint
97
98
  self.allowed_parameters = allowed_parameters
98
99
  if isinstance(provider, type):
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  from collections.abc import AsyncIterator, Callable, Iterable
5
5
  from functools import wraps
6
- from typing import Any, Generic, Type, TypeVar
6
+ from typing import Any, Generic, TypeVar
7
7
 
8
8
  from pydantic import Field, field_validator
9
9
 
@@ -1,9 +1,8 @@
1
1
  import contextlib
2
2
 
3
+ import lionfuncs as ln
3
4
  from pydantic import Field, field_validator
4
5
 
5
- from lionagi.libs import SysUtil
6
-
7
6
  from .abc import Element, ItemNotFoundError, LionIDable, Ordering, get_lion_id
8
7
  from .util import _validate_order
9
8
 
@@ -90,7 +89,7 @@ class Progression(Element, Ordering):
90
89
  """Remove the next occurrence of an item from the progression."""
91
90
  if item in self:
92
91
  item = self._validate_order(item)
93
- l_ = SysUtil.create_copy(self.order)
92
+ l_ = ln.copy(self.order)
94
93
 
95
94
  with contextlib.suppress(Exception):
96
95
  for i in item:
@@ -143,7 +142,7 @@ class Progression(Element, Ordering):
143
142
  def __radd__(self, other):
144
143
  if not isinstance(other, Progression):
145
144
  _copy = self.copy()
146
- l_ = SysUtil.create_copy(_copy.order)
145
+ l_ = ln.copy(_copy.order)
147
146
  l_.insert(0, get_lion_id(other))
148
147
  _copy.order = l_
149
148
  return _copy
@@ -190,7 +189,7 @@ class Progression(Element, Ordering):
190
189
 
191
190
  def __list__(self):
192
191
  """Return a list representation of the progression."""
193
- return SysUtil.create_copy(self.order)
192
+ return ln.copy(self.order)
194
193
 
195
194
  def __reversed__(self):
196
195
  """Return a reversed progression."""
@@ -1,93 +1,3 @@
1
- from __future__ import annotations
1
+ from lionagi.operations.select import select
2
2
 
3
- from collections.abc import Callable
4
- from enum import Enum
5
-
6
- from lionfuncs import choose_most_similar
7
- from pydantic import BaseModel
8
-
9
- from lionagi.core.director.models import ReasonModel
10
- from lionagi.core.session.branch import Branch
11
-
12
- from .utils import is_enum
13
-
14
- PROMPT = "Please select up to {max_num_selections} items from the following list {choices}. Provide the selection(s), and no comments from you"
15
-
16
-
17
- class SelectionModel(BaseModel):
18
- selected: list[str | Enum]
19
-
20
-
21
- class ReasonSelectionModel(BaseModel):
22
- selected: list[str | Enum]
23
- reason: ReasonModel
24
-
25
-
26
- async def select(
27
- choices: list[str] | type[Enum],
28
- max_num_selections: int = 1,
29
- instruction=None,
30
- context=None,
31
- system=None,
32
- sender=None,
33
- recipient=None,
34
- reason: bool = False,
35
- return_enum: bool = False,
36
- enum_parser: Callable = None, # parse the model string response to appropriate type
37
- branch: Branch = None,
38
- return_pydantic_model=False,
39
- **kwargs, # additional chat arguments
40
- ):
41
- selections = []
42
- if return_enum and not is_enum(choices):
43
- raise ValueError("return_enum can only be True if choices is an Enum")
44
-
45
- if is_enum(choices):
46
- selections = [selection.value for selection in choices]
47
- else:
48
- selections = choices
49
-
50
- prompt = PROMPT.format(
51
- max_num_selections=max_num_selections, choices=selections
52
- )
53
-
54
- if instruction:
55
- prompt = f"{instruction}\n\n{prompt} \n\n "
56
-
57
- branch = branch or Branch()
58
- response: SelectionModel | ReasonSelectionModel | str = await branch.chat(
59
- instruction=prompt,
60
- context=context,
61
- system=system,
62
- sender=sender,
63
- recipient=recipient,
64
- pydantic_model=SelectionModel if not reason else ReasonSelectionModel,
65
- return_pydantic_model=True,
66
- **kwargs,
67
- )
68
-
69
- selected = response
70
- if isinstance(response, SelectionModel | ReasonSelectionModel):
71
- selected = response.selected
72
- selected = [selected] if not isinstance(selected, list) else selected
73
- corrected_selections = [
74
- choose_most_similar(selection, selections) for selection in selected
75
- ]
76
-
77
- if return_enum:
78
- out = []
79
- if not enum_parser:
80
- enum_parser = lambda x: x
81
- for selection in corrected_selections:
82
- selection = enum_parser(selection)
83
- for member in choices.__members__.values():
84
- if member.value == selection:
85
- out.append(member)
86
- corrected_selections = out
87
-
88
- if return_pydantic_model:
89
- if not isinstance(response, SelectionModel | ReasonSelectionModel):
90
- return SelectionModel(selected=corrected_selections)
91
- response.selected = corrected_selections
92
- return response
93
- return corrected_selections
3
+ __all__ = ["select"]
@@ -1,4 +1,4 @@
1
- from lionfuncs import choose_most_similar
1
+ from lionfuncs import string_similarity
2
2
 
3
3
  from lionagi.core.rule.base import Rule
4
4
 
@@ -45,4 +45,4 @@ class ChoiceRule(Rule):
45
45
  Returns:
46
46
  str: The most similar value from the set of predefined choices.
47
47
  """
48
- return choose_most_similar(value, self.keys)
48
+ return string_similarity(value, self.keys, choose_most_similar=True)
@@ -2,9 +2,9 @@ import asyncio
2
2
  import contextlib
3
3
  import re
4
4
  from abc import ABC
5
- from typing import Any, Optional
5
+ from typing import Any
6
6
 
7
- from lionfuncs import extract_json_block, to_dict, validate_mapping
7
+ from lionfuncs import extract_block, to_dict, validate_mapping
8
8
 
9
9
  from lionagi.core.collections.abc import ActionError
10
10
  from lionagi.core.message import ActionRequest, ActionResponse, Instruction
@@ -1156,7 +1156,7 @@ class DirectiveMixin(ABC):
1156
1156
  return to_dict(out_, fuzzy_parse=True)
1157
1157
 
1158
1158
  with contextlib.suppress(Exception):
1159
- return extract_json_block(out_)
1159
+ return extract_block(out_)
1160
1160
 
1161
1161
  with contextlib.suppress(Exception):
1162
1162
  match = re.search(r"```json\n({.*?})\n```", out_, re.DOTALL)
File without changes
File without changes