lionagi 0.6.1__py3-none-any.whl → 0.7.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- lionagi/libs/token_transform/__init__.py +0 -0
- lionagi/libs/token_transform/llmlingua.py +1 -0
- lionagi/libs/token_transform/perplexity.py +439 -0
- lionagi/libs/token_transform/synthlang.py +409 -0
- lionagi/operations/ReAct/ReAct.py +126 -0
- lionagi/operations/ReAct/utils.py +28 -0
- lionagi/operations/__init__.py +1 -9
- lionagi/operations/_act/act.py +73 -0
- lionagi/operations/chat/__init__.py +3 -0
- lionagi/operations/chat/chat.py +173 -0
- lionagi/operations/communicate/__init__.py +0 -0
- lionagi/operations/communicate/communicate.py +167 -0
- lionagi/operations/instruct/__init__.py +3 -0
- lionagi/operations/instruct/instruct.py +29 -0
- lionagi/operations/interpret/__init__.py +3 -0
- lionagi/operations/interpret/interpret.py +40 -0
- lionagi/operations/operate/__init__.py +3 -0
- lionagi/operations/operate/operate.py +189 -0
- lionagi/operations/parse/__init__.py +3 -0
- lionagi/operations/parse/parse.py +125 -0
- lionagi/operations/select/__init__.py +0 -4
- lionagi/operations/select/select.py +11 -30
- lionagi/operations/select/utils.py +13 -2
- lionagi/operations/translate/__init__.py +0 -0
- lionagi/operations/translate/translate.py +47 -0
- lionagi/operations/types.py +16 -0
- lionagi/operatives/action/manager.py +20 -21
- lionagi/operatives/strategies/__init__.py +3 -0
- lionagi/session/branch.py +1098 -929
- lionagi/version.py +1 -1
- {lionagi-0.6.1.dist-info → lionagi-0.7.0.dist-info}/METADATA +1 -1
- {lionagi-0.6.1.dist-info → lionagi-0.7.0.dist-info}/RECORD +45 -26
- lionagi/libs/compress/models.py +0 -66
- lionagi/libs/compress/utils.py +0 -69
- lionagi/operations/select/prompt.py +0 -5
- /lionagi/{libs/compress → operations/ReAct}/__init__.py +0 -0
- /lionagi/operations/{strategies → _act}/__init__.py +0 -0
- /lionagi/{operations → operatives}/strategies/base.py +0 -0
- /lionagi/{operations → operatives}/strategies/concurrent.py +0 -0
- /lionagi/{operations → operatives}/strategies/concurrent_chunk.py +0 -0
- /lionagi/{operations → operatives}/strategies/concurrent_sequential_chunk.py +0 -0
- /lionagi/{operations → operatives}/strategies/params.py +0 -0
- /lionagi/{operations → operatives}/strategies/sequential.py +0 -0
- /lionagi/{operations → operatives}/strategies/sequential_chunk.py +0 -0
- /lionagi/{operations → operatives}/strategies/sequential_concurrent_chunk.py +0 -0
- /lionagi/{operations → operatives}/strategies/utils.py +0 -0
- {lionagi-0.6.1.dist-info → lionagi-0.7.0.dist-info}/WHEEL +0 -0
- {lionagi-0.6.1.dist-info → lionagi-0.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,125 @@
|
|
1
|
+
# Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
4
|
+
|
5
|
+
from typing import TYPE_CHECKING, Any, Literal
|
6
|
+
|
7
|
+
from pydantic import BaseModel
|
8
|
+
|
9
|
+
from lionagi.libs.validate.fuzzy_validate_mapping import fuzzy_validate_mapping
|
10
|
+
from lionagi.operatives.types import Operative
|
11
|
+
from lionagi.utils import breakdown_pydantic_annotation
|
12
|
+
|
13
|
+
if TYPE_CHECKING:
|
14
|
+
from lionagi.session.branch import Branch
|
15
|
+
|
16
|
+
|
17
|
+
async def parse(
|
18
|
+
branch: "Branch",
|
19
|
+
text: str,
|
20
|
+
handle_validation: Literal[
|
21
|
+
"raise", "return_value", "return_none"
|
22
|
+
] = "return_value",
|
23
|
+
max_retries: int = 3,
|
24
|
+
request_type: type[BaseModel] = None,
|
25
|
+
operative: Operative = None,
|
26
|
+
similarity_algo="jaro_winkler",
|
27
|
+
similarity_threshold: float = 0.85,
|
28
|
+
fuzzy_match: bool = True,
|
29
|
+
handle_unmatched: Literal[
|
30
|
+
"ignore", "raise", "remove", "fill", "force"
|
31
|
+
] = "force",
|
32
|
+
fill_value: Any = None,
|
33
|
+
fill_mapping: dict[str, Any] | None = None,
|
34
|
+
strict: bool = False,
|
35
|
+
suppress_conversion_errors: bool = False,
|
36
|
+
response_format=None,
|
37
|
+
):
|
38
|
+
"""Attempts to parse text into a structured Pydantic model.
|
39
|
+
|
40
|
+
Uses optional fuzzy matching to handle partial or unclear fields.
|
41
|
+
|
42
|
+
Args:
|
43
|
+
text (str): The raw text to parse.
|
44
|
+
handle_validation (Literal["raise","return_value","return_none"]):
|
45
|
+
What to do if parsing fails. Defaults to "return_value".
|
46
|
+
max_retries (int):
|
47
|
+
How many times to retry parsing if it fails.
|
48
|
+
request_type (type[BaseModel], optional):
|
49
|
+
The Pydantic model to parse into.
|
50
|
+
operative (Operative, optional):
|
51
|
+
If provided, uses its model and max_retries setting.
|
52
|
+
similarity_algo (str):
|
53
|
+
The similarity algorithm for fuzzy field matching.
|
54
|
+
similarity_threshold (float):
|
55
|
+
A threshold for fuzzy matching (0.0 - 1.0).
|
56
|
+
fuzzy_match (bool):
|
57
|
+
If True, tries to match unrecognized keys to known ones.
|
58
|
+
handle_unmatched (Literal["ignore","raise","remove","fill","force"]):
|
59
|
+
How to handle unmatched fields.
|
60
|
+
fill_value (Any):
|
61
|
+
A default value used when fill is needed.
|
62
|
+
fill_mapping (dict[str, Any] | None):
|
63
|
+
A mapping from field -> fill value override.
|
64
|
+
strict (bool):
|
65
|
+
If True, raises errors on ambiguous fields or data types.
|
66
|
+
suppress_conversion_errors (bool):
|
67
|
+
If True, logs or ignores errors during data conversion.
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
BaseModel | Any | None:
|
71
|
+
The parsed model instance, or a dict/string/None depending
|
72
|
+
on the handling mode.
|
73
|
+
"""
|
74
|
+
_should_try = True
|
75
|
+
num_try = 0
|
76
|
+
response_model = text
|
77
|
+
if operative is not None:
|
78
|
+
max_retries = operative.max_retries
|
79
|
+
response_format = operative.request_type
|
80
|
+
|
81
|
+
while (
|
82
|
+
_should_try
|
83
|
+
and num_try < max_retries
|
84
|
+
and not isinstance(response_model, BaseModel)
|
85
|
+
):
|
86
|
+
num_try += 1
|
87
|
+
_, res = await branch.chat(
|
88
|
+
instruction="reformat text into specified model",
|
89
|
+
guidane="follow the required response format, using the model schema as a guide",
|
90
|
+
context=[{"text_to_format": text}],
|
91
|
+
response_format=response_format or request_type,
|
92
|
+
sender=branch.user,
|
93
|
+
recipient=branch.id,
|
94
|
+
imodel=branch.parse_model,
|
95
|
+
return_ins_res_message=True,
|
96
|
+
)
|
97
|
+
if operative is not None:
|
98
|
+
response_model = operative.update_response_model(res.response)
|
99
|
+
else:
|
100
|
+
response_model = fuzzy_validate_mapping(
|
101
|
+
res.response,
|
102
|
+
breakdown_pydantic_annotation(request_type),
|
103
|
+
similarity_algo=similarity_algo,
|
104
|
+
similarity_threshold=similarity_threshold,
|
105
|
+
fuzzy_match=fuzzy_match,
|
106
|
+
handle_unmatched=handle_unmatched,
|
107
|
+
fill_value=fill_value,
|
108
|
+
fill_mapping=fill_mapping,
|
109
|
+
strict=strict,
|
110
|
+
suppress_conversion_errors=suppress_conversion_errors,
|
111
|
+
)
|
112
|
+
response_model = request_type.model_validate(response_model)
|
113
|
+
|
114
|
+
if not isinstance(response_model, BaseModel):
|
115
|
+
match handle_validation:
|
116
|
+
case "return_value":
|
117
|
+
return response_model
|
118
|
+
case "return_none":
|
119
|
+
return None
|
120
|
+
case "raise":
|
121
|
+
raise ValueError(
|
122
|
+
"Failed to parse response into request format"
|
123
|
+
)
|
124
|
+
|
125
|
+
return response_model
|
@@ -2,56 +2,37 @@
|
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
|
-
|
6
5
|
from enum import Enum
|
7
|
-
from typing import Any
|
6
|
+
from typing import TYPE_CHECKING, Any
|
8
7
|
|
9
|
-
from pydantic import BaseModel
|
8
|
+
from pydantic import BaseModel
|
10
9
|
|
11
10
|
from lionagi.operatives.types import Instruct
|
12
|
-
from lionagi.session.branch import Branch
|
13
|
-
|
14
|
-
from .prompt import PROMPT
|
15
|
-
from .utils import parse_selection, parse_to_representation
|
16
11
|
|
12
|
+
from .utils import SelectionModel
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
selected: list[Any] = Field(default_factory=list)
|
14
|
+
if TYPE_CHECKING:
|
15
|
+
from lionagi.session.branch import Branch
|
22
16
|
|
23
17
|
|
24
18
|
async def select(
|
19
|
+
branch: "Branch",
|
25
20
|
instruct: Instruct | dict[str, Any],
|
26
21
|
choices: list[str] | type[Enum] | dict[str, Any],
|
27
22
|
max_num_selections: int = 1,
|
28
|
-
branch: Branch | None = None,
|
29
23
|
branch_kwargs: dict[str, Any] | None = None,
|
30
24
|
return_branch: bool = False,
|
31
25
|
verbose: bool = False,
|
32
26
|
**kwargs: Any,
|
33
|
-
) -> SelectionModel | tuple[SelectionModel, Branch]:
|
34
|
-
"""Perform a selection operation from given choices.
|
35
|
-
|
36
|
-
Args:
|
37
|
-
instruct: Instruction model or dictionary.
|
38
|
-
choices: Options to select from.
|
39
|
-
max_num_selections: Maximum selections allowed.
|
40
|
-
branch: Existing branch or None to create a new one.
|
41
|
-
branch_kwargs: Additional arguments for branch creation.
|
42
|
-
return_branch: If True, return the branch with the selection.
|
43
|
-
verbose: Whether to enable verbose output.
|
44
|
-
**kwargs: Additional keyword arguments.
|
45
|
-
|
46
|
-
Returns:
|
47
|
-
A SelectionModel instance, optionally with the branch.
|
48
|
-
"""
|
27
|
+
) -> SelectionModel | tuple[SelectionModel, "Branch"]:
|
49
28
|
if verbose:
|
50
29
|
print(f"Starting selection with up to {max_num_selections} choices.")
|
51
30
|
|
31
|
+
from .utils import SelectionModel, parse_selection, parse_to_representation
|
32
|
+
|
52
33
|
branch = branch or Branch(**(branch_kwargs or {}))
|
53
34
|
selections, contents = parse_to_representation(choices)
|
54
|
-
prompt = PROMPT.format(
|
35
|
+
prompt = SelectionModel.PROMPT.format(
|
55
36
|
max_num_selections=max_num_selections, choices=selections
|
56
37
|
)
|
57
38
|
|
@@ -73,7 +54,7 @@ async def select(
|
|
73
54
|
instruct["context"] = context
|
74
55
|
|
75
56
|
response_model: SelectionModel = await branch.operate(
|
76
|
-
|
57
|
+
response_format=SelectionModel,
|
77
58
|
**kwargs,
|
78
59
|
**instruct,
|
79
60
|
)
|
@@ -4,14 +4,25 @@
|
|
4
4
|
|
5
5
|
import inspect
|
6
6
|
from enum import Enum
|
7
|
-
from typing import Any
|
7
|
+
from typing import Any, ClassVar
|
8
8
|
|
9
|
-
from pydantic import BaseModel, JsonValue
|
9
|
+
from pydantic import BaseModel, Field, JsonValue
|
10
10
|
|
11
11
|
from lionagi.libs.validate.string_similarity import string_similarity
|
12
12
|
from lionagi.utils import is_same_dtype
|
13
13
|
|
14
14
|
|
15
|
+
# TODO: Make select a field to be added into a model, much like reason and action
|
16
|
+
class SelectionModel(BaseModel):
|
17
|
+
"""Model representing the selection output."""
|
18
|
+
|
19
|
+
PROMPT: ClassVar[str] = (
|
20
|
+
"Please select up to {max_num_selections} items from the following list {choices}. Provide the selection(s) into appropriate field in format required, and no comments from you"
|
21
|
+
)
|
22
|
+
|
23
|
+
selected: list[Any] = Field(default_factory=list)
|
24
|
+
|
25
|
+
|
15
26
|
def parse_to_representation(
|
16
27
|
choices: Enum | dict | list | tuple | set,
|
17
28
|
) -> tuple[list[str], JsonValue]:
|
File without changes
|
@@ -0,0 +1,47 @@
|
|
1
|
+
from typing import TYPE_CHECKING, Literal
|
2
|
+
|
3
|
+
from lionagi.service.imodel import iModel
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from lionagi.session.branch import Branch
|
7
|
+
|
8
|
+
|
9
|
+
async def translate(
|
10
|
+
branch: "Branch",
|
11
|
+
text: str,
|
12
|
+
technique: Literal["SynthLang"] = "SynthLang",
|
13
|
+
technique_kwargs: dict = None,
|
14
|
+
compress: bool = False,
|
15
|
+
chat_model: iModel = None,
|
16
|
+
compress_model: iModel = None,
|
17
|
+
compression_ratio: float = 0.2,
|
18
|
+
compress_kwargs=None,
|
19
|
+
verbose: bool = True,
|
20
|
+
new_branch: bool = True,
|
21
|
+
**kwargs,
|
22
|
+
):
|
23
|
+
if technique == "SynthLang":
|
24
|
+
from lionagi.libs.token_transform.synthlang import (
|
25
|
+
translate_to_synthlang,
|
26
|
+
)
|
27
|
+
|
28
|
+
if not technique_kwargs:
|
29
|
+
technique_kwargs = {}
|
30
|
+
if not technique_kwargs.get("template_name"):
|
31
|
+
technique_kwargs["template_name"] = "symbolic_systems"
|
32
|
+
|
33
|
+
technique_kwargs = {**technique_kwargs, **kwargs}
|
34
|
+
|
35
|
+
return await translate_to_synthlang(
|
36
|
+
text=text,
|
37
|
+
compress=compress,
|
38
|
+
chat_model=chat_model or branch.chat_model,
|
39
|
+
compress_model=compress_model,
|
40
|
+
compression_ratio=compression_ratio,
|
41
|
+
compress_kwargs=compress_kwargs,
|
42
|
+
verbose=verbose,
|
43
|
+
branch=branch if not new_branch else None,
|
44
|
+
**technique_kwargs,
|
45
|
+
)
|
46
|
+
|
47
|
+
raise ValueError(f"Technique {technique} is not supported.")
|
lionagi/operations/types.py
CHANGED
@@ -3,11 +3,27 @@
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
5
|
from .brainstorm.brainstorm import brainstorm
|
6
|
+
from .chat.chat import chat
|
7
|
+
from .communicate.communicate import communicate
|
8
|
+
from .instruct.instruct import instruct
|
9
|
+
from .interpret.interpret import interpret
|
10
|
+
from .operate.operate import operate
|
11
|
+
from .parse.parse import parse
|
6
12
|
from .plan.plan import plan
|
13
|
+
from .ReAct.ReAct import ReAct
|
7
14
|
from .select.select import select
|
15
|
+
from .translate.translate import translate
|
8
16
|
|
9
17
|
__all__ = (
|
10
18
|
"brainstorm",
|
11
19
|
"plan",
|
12
20
|
"select",
|
21
|
+
"chat",
|
22
|
+
"communicate",
|
23
|
+
"instruct",
|
24
|
+
"interpret",
|
25
|
+
"operate",
|
26
|
+
"parse",
|
27
|
+
"ReAct",
|
28
|
+
"translate",
|
13
29
|
)
|
@@ -5,8 +5,7 @@
|
|
5
5
|
from typing import Any
|
6
6
|
|
7
7
|
from lionagi.protocols._concepts import Manager
|
8
|
-
from lionagi.protocols.generic.event import
|
9
|
-
from lionagi.protocols.generic.log import Log
|
8
|
+
from lionagi.protocols.generic.event import Execution
|
10
9
|
from lionagi.protocols.messages.action_request import ActionRequest
|
11
10
|
from lionagi.utils import to_list
|
12
11
|
|
@@ -113,19 +112,28 @@ class ActionManager(Manager):
|
|
113
112
|
]
|
114
113
|
|
115
114
|
def match_tool(
|
116
|
-
self, action_request: ActionRequest | ActionRequestModel
|
115
|
+
self, action_request: ActionRequest | ActionRequestModel | dict
|
117
116
|
) -> FunctionCalling:
|
118
|
-
if not isinstance(
|
117
|
+
if not isinstance(
|
118
|
+
action_request, ActionRequest | ActionRequestModel | dict
|
119
|
+
):
|
119
120
|
raise TypeError(f"Unsupported type {type(action_request)}")
|
120
121
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
122
|
+
func = (
|
123
|
+
action_request["function"]
|
124
|
+
if isinstance(action_request, dict)
|
125
|
+
else action_request.function
|
126
|
+
)
|
127
|
+
args = (
|
128
|
+
action_request["arguments"]
|
129
|
+
if isinstance(action_request, dict)
|
130
|
+
else action_request.arguments
|
128
131
|
)
|
132
|
+
tool = self.registry.get(func, None)
|
133
|
+
|
134
|
+
if not isinstance(tool, Tool):
|
135
|
+
raise ValueError(f"Function {func} is not registered.")
|
136
|
+
return FunctionCalling(func_tool=tool, arguments=args)
|
129
137
|
|
130
138
|
async def invoke(
|
131
139
|
self, func_call: ActionRequestModel | ActionRequest
|
@@ -148,16 +156,7 @@ class ActionManager(Manager):
|
|
148
156
|
Raises:
|
149
157
|
ValueError: If function not registered or call format invalid.
|
150
158
|
"""
|
151
|
-
|
152
|
-
function_calling = self.match_tool(func_call)
|
153
|
-
except ValueError as e:
|
154
|
-
return Log(
|
155
|
-
content={
|
156
|
-
"event_type": "function_call",
|
157
|
-
"status": EventStatus.FAILED,
|
158
|
-
"error": str(e),
|
159
|
-
}
|
160
|
-
)
|
159
|
+
function_calling = self.match_tool(func_call)
|
161
160
|
await function_calling.invoke()
|
162
161
|
return function_calling
|
163
162
|
|