lionagi 0.0.114__py3-none-any.whl → 0.0.116__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.
- lionagi/__init__.py +7 -4
- lionagi/bridge/__init__.py +19 -4
- lionagi/bridge/langchain.py +23 -3
- lionagi/bridge/llama_index.py +5 -3
- lionagi/configs/__init__.py +1 -1
- lionagi/configs/oai_configs.py +88 -1
- lionagi/core/__init__.py +6 -9
- lionagi/core/conversations/__init__.py +5 -0
- lionagi/core/conversations/conversation.py +107 -0
- lionagi/core/flows/__init__.py +8 -0
- lionagi/core/flows/flow.py +8 -0
- lionagi/core/flows/flow_util.py +62 -0
- lionagi/core/instruction_set/__init__.py +5 -0
- lionagi/core/instruction_set/instruction_sets.py +7 -0
- lionagi/core/sessions/__init__.py +5 -0
- lionagi/core/sessions/sessions.py +187 -0
- lionagi/endpoints/__init__.py +5 -0
- lionagi/endpoints/assistants.py +0 -0
- lionagi/endpoints/audio.py +17 -0
- lionagi/endpoints/chatcompletion.py +54 -0
- lionagi/endpoints/embeddings.py +0 -0
- lionagi/endpoints/finetune.py +0 -0
- lionagi/endpoints/image.py +0 -0
- lionagi/endpoints/moderation.py +0 -0
- lionagi/endpoints/vision.py +0 -0
- lionagi/{loader → loaders}/__init__.py +7 -1
- lionagi/{loader → loaders}/chunker.py +6 -12
- lionagi/{utils/load_utils.py → loaders/load_util.py} +47 -6
- lionagi/{loader → loaders}/reader.py +4 -12
- lionagi/messages/__init__.py +11 -0
- lionagi/messages/instruction.py +15 -0
- lionagi/messages/message.py +110 -0
- lionagi/messages/response.py +33 -0
- lionagi/messages/system.py +12 -0
- lionagi/objs/__init__.py +10 -6
- lionagi/objs/abc_objs.py +39 -0
- lionagi/objs/async_queue.py +135 -0
- lionagi/objs/messenger.py +70 -148
- lionagi/objs/status_tracker.py +37 -0
- lionagi/objs/{tool_registry.py → tool_manager.py} +8 -6
- lionagi/schema/__init__.py +3 -3
- lionagi/schema/base_node.py +251 -0
- lionagi/schema/base_tool.py +8 -3
- lionagi/schema/data_logger.py +2 -3
- lionagi/schema/data_node.py +37 -0
- lionagi/services/__init__.py +1 -4
- lionagi/services/base_api_service.py +15 -5
- lionagi/services/oai.py +2 -2
- lionagi/services/openrouter.py +2 -3
- lionagi/structures/graph.py +96 -0
- lionagi/{structure → structures}/relationship.py +10 -2
- lionagi/structures/structure.py +102 -0
- lionagi/tests/test_api_util.py +46 -0
- lionagi/tests/test_call_util.py +115 -0
- lionagi/tests/test_convert_util.py +202 -0
- lionagi/tests/test_encrypt_util.py +33 -0
- lionagi/tests/{test_flatten_util.py → test_flat_util.py} +1 -1
- lionagi/tests/test_io_util.py +0 -0
- lionagi/tests/test_sys_util.py +0 -0
- lionagi/tools/__init__.py +5 -0
- lionagi/tools/tool_util.py +7 -0
- lionagi/utils/__init__.py +55 -35
- lionagi/utils/api_util.py +19 -17
- lionagi/utils/call_util.py +2 -1
- lionagi/utils/convert_util.py +229 -0
- lionagi/utils/encrypt_util.py +16 -0
- lionagi/utils/flat_util.py +38 -0
- lionagi/utils/io_util.py +2 -2
- lionagi/utils/sys_util.py +45 -10
- lionagi/version.py +1 -1
- {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/METADATA +2 -2
- lionagi-0.0.116.dist-info/RECORD +110 -0
- lionagi/core/conversations.py +0 -108
- lionagi/core/flows.py +0 -1
- lionagi/core/instruction_sets.py +0 -1
- lionagi/core/messages.py +0 -166
- lionagi/core/sessions.py +0 -297
- lionagi/schema/base_schema.py +0 -252
- lionagi/services/chatcompletion.py +0 -48
- lionagi/services/service_objs.py +0 -282
- lionagi/structure/structure.py +0 -160
- lionagi/tools/coder.py +0 -1
- lionagi/tools/sandbox.py +0 -1
- lionagi/utils/tool_util.py +0 -92
- lionagi/utils/type_util.py +0 -81
- lionagi-0.0.114.dist-info/RECORD +0 -84
- /lionagi/configs/{openrouter_config.py → openrouter_configs.py} +0 -0
- /lionagi/{datastore → datastores}/__init__.py +0 -0
- /lionagi/{datastore → datastores}/chroma.py +0 -0
- /lionagi/{datastore → datastores}/deeplake.py +0 -0
- /lionagi/{datastore → datastores}/elasticsearch.py +0 -0
- /lionagi/{datastore → datastores}/lantern.py +0 -0
- /lionagi/{datastore → datastores}/pinecone.py +0 -0
- /lionagi/{datastore → datastores}/postgres.py +0 -0
- /lionagi/{datastore → datastores}/qdrant.py +0 -0
- /lionagi/{structure → structures}/__init__.py +0 -0
- {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/LICENSE +0 -0
- {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/WHEEL +0 -0
- {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/top_level.txt +0 -0
lionagi/services/service_objs.py
DELETED
@@ -1,282 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
from abc import ABC, abstractmethod
|
3
|
-
from dataclasses import dataclass
|
4
|
-
from typing import Any, Callable, Dict, NoReturn
|
5
|
-
|
6
|
-
|
7
|
-
# should be fine ------------------------------------------------------------------
|
8
|
-
@dataclass
|
9
|
-
class StatusTracker:
|
10
|
-
"""
|
11
|
-
Class for keeping track of various task statuses.
|
12
|
-
|
13
|
-
This class serves as a simple way to monitor different types of task
|
14
|
-
outcomes and errors within a system. It uses dataclasses for easy
|
15
|
-
creation and management of state.
|
16
|
-
|
17
|
-
Attributes:
|
18
|
-
num_tasks_started:
|
19
|
-
The number of tasks that have been initiated.
|
20
|
-
num_tasks_in_progress:
|
21
|
-
The number of tasks currently being processed.
|
22
|
-
num_tasks_succeeded:
|
23
|
-
The number of tasks that have completed successfully.
|
24
|
-
num_tasks_failed:
|
25
|
-
The number of tasks that have failed.
|
26
|
-
num_rate_limit_errors:
|
27
|
-
The number of tasks that failed due to rate limiting.
|
28
|
-
num_api_errors:
|
29
|
-
The number of tasks that failed due to API errors.
|
30
|
-
num_other_errors:
|
31
|
-
The number of tasks that failed due to other errors.
|
32
|
-
"""
|
33
|
-
num_tasks_started: int = 0
|
34
|
-
num_tasks_in_progress: int = 0
|
35
|
-
num_tasks_succeeded: int = 0
|
36
|
-
num_tasks_failed: int = 0
|
37
|
-
num_rate_limit_errors: int = 0
|
38
|
-
num_api_errors: int = 0
|
39
|
-
num_other_errors: int = 0
|
40
|
-
|
41
|
-
|
42
|
-
class AsyncQueue:
|
43
|
-
"""
|
44
|
-
A queue class that handles asynchronous operations using asyncio.
|
45
|
-
|
46
|
-
This class provides an asynchronous queue that can enqueue items, process them
|
47
|
-
asynchronously, and support graceful shutdowns. It is designed to facilitate
|
48
|
-
concurrent task processing in an orderly and controlled manner.
|
49
|
-
|
50
|
-
Attributes:
|
51
|
-
queue (asyncio.Queue):
|
52
|
-
A queue to hold items for asynchronous processing.
|
53
|
-
_stop_event (asyncio.Event):
|
54
|
-
An event to signal when the queue should stop processing.
|
55
|
-
|
56
|
-
Methods:
|
57
|
-
enqueue(item):
|
58
|
-
Add an item to the queue for processing.
|
59
|
-
dequeue():
|
60
|
-
Remove and return an item from the queue.
|
61
|
-
join():
|
62
|
-
Wait until all items in the queue have been processed.
|
63
|
-
stop():
|
64
|
-
Signal to stop processing new items in the queue.
|
65
|
-
stopped():
|
66
|
-
Check if the queue has been signaled to stop.
|
67
|
-
process_requests(func):
|
68
|
-
Process items using a provided function.
|
69
|
-
"""
|
70
|
-
|
71
|
-
def __init__(self) -> None:
|
72
|
-
"""
|
73
|
-
Initializes an AsyncQueue object with an empty asyncio Queue and a stop event.
|
74
|
-
"""
|
75
|
-
self.queue = asyncio.Queue()
|
76
|
-
self._stop_event = asyncio.Event()
|
77
|
-
|
78
|
-
async def enqueue(self, item: Any) -> None:
|
79
|
-
"""
|
80
|
-
Asynchronously add an item to the queue for processing.
|
81
|
-
|
82
|
-
Parameters:
|
83
|
-
item (Any): The item to be added to the queue.
|
84
|
-
|
85
|
-
Example:
|
86
|
-
>>> async_queue = AsyncQueue()
|
87
|
-
>>> asyncio.run(async_queue.enqueue('Task 1'))
|
88
|
-
"""
|
89
|
-
await self.queue.put(item)
|
90
|
-
|
91
|
-
async def dequeue(self) -> Any:
|
92
|
-
"""
|
93
|
-
Asynchronously remove and return an item from the queue.
|
94
|
-
|
95
|
-
If the queue is empty, this method will wait until an item is available.
|
96
|
-
|
97
|
-
Returns:
|
98
|
-
Any: The next item from the queue.
|
99
|
-
|
100
|
-
Example:
|
101
|
-
>>> async_queue = AsyncQueue()
|
102
|
-
>>> asyncio.run(async_queue.enqueue('Task 1'))
|
103
|
-
>>> asyncio.run(async_queue.dequeue())
|
104
|
-
'Task 1'
|
105
|
-
"""
|
106
|
-
return await self.queue.get()
|
107
|
-
|
108
|
-
async def join(self) -> None:
|
109
|
-
"""
|
110
|
-
Asynchronously wait until all items in the queue have been processed.
|
111
|
-
|
112
|
-
This method blocks until every item that has been enqueued is processed,
|
113
|
-
ensuring that all tasks are completed.
|
114
|
-
|
115
|
-
Example:
|
116
|
-
>>> async_queue = AsyncQueue()
|
117
|
-
>>> asyncio.run(async_queue.enqueue('Task 1'))
|
118
|
-
>>> asyncio.run(async_queue.join()) # This will block until 'Task 1' is processed.
|
119
|
-
"""
|
120
|
-
await self.queue.join()
|
121
|
-
|
122
|
-
async def stop(self) -> None:
|
123
|
-
"""
|
124
|
-
Signal the queue to stop processing new items.
|
125
|
-
|
126
|
-
Once called, the queue will not process any new items after the current ones
|
127
|
-
are completed, allowing for a graceful shutdown.
|
128
|
-
|
129
|
-
Example:
|
130
|
-
>>> async_queue = AsyncQueue()
|
131
|
-
>>> asyncio.run(async_queue.stop()) # This signals the queue to stop processing.
|
132
|
-
"""
|
133
|
-
self._stop_event.set()
|
134
|
-
|
135
|
-
def stopped(self) -> bool:
|
136
|
-
"""
|
137
|
-
Check if the queue has been signaled to stop processing.
|
138
|
-
|
139
|
-
Returns:
|
140
|
-
bool: True if a stop has been signaled, False otherwise.
|
141
|
-
|
142
|
-
Example:
|
143
|
-
>>> async_queue = AsyncQueue()
|
144
|
-
>>> asyncio.run(async_queue.stop())
|
145
|
-
>>> async_queue.stopped()
|
146
|
-
True
|
147
|
-
"""
|
148
|
-
return self._stop_event.is_set()
|
149
|
-
|
150
|
-
async def process_requests(self, func: Callable[[Any], Any]) -> None:
|
151
|
-
"""
|
152
|
-
Asynchronously process items from the queue using the provided function.
|
153
|
-
|
154
|
-
Continuously dequeues items and applies the given function to each.
|
155
|
-
The processing stops when the queue is signaled to stop or a sentinel value (`None`) is dequeued.
|
156
|
-
|
157
|
-
Parameters:
|
158
|
-
func (Callable[[Any], Any]): A coroutine function to process items from the queue.
|
159
|
-
|
160
|
-
Example:
|
161
|
-
>>> async def sample_processing(task):
|
162
|
-
... print("Processing:", task)
|
163
|
-
>>> async_queue = AsyncQueue()
|
164
|
-
>>> asyncio.run(async_queue.enqueue('Task 1'))
|
165
|
-
>>> asyncio.run(async_queue.process_requests(sample_processing))
|
166
|
-
Processing: Task 1
|
167
|
-
"""
|
168
|
-
while not self.stopped():
|
169
|
-
item = await self.dequeue()
|
170
|
-
if item is None: # Using `None` as a sentinel value to cease processing.
|
171
|
-
await self.stop()
|
172
|
-
break
|
173
|
-
await func(item)
|
174
|
-
|
175
|
-
|
176
|
-
class BaseService(ABC):
|
177
|
-
|
178
|
-
@abstractmethod
|
179
|
-
def __init__(self) -> None:
|
180
|
-
...
|
181
|
-
|
182
|
-
@abstractmethod
|
183
|
-
async def serve(self) -> Any:
|
184
|
-
...
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
class RateLimiter(ABC):
|
189
|
-
"""
|
190
|
-
An abstract base class for rate limiting mechanisms.
|
191
|
-
|
192
|
-
This class defines a structure for rate limiters, which are used to control the frequency
|
193
|
-
of requests sent to or received from a network interface controller or an API.
|
194
|
-
|
195
|
-
Attributes:
|
196
|
-
max_requests_per_minute (int):
|
197
|
-
Maximum number of requests permitted per minute.
|
198
|
-
max_tokens_per_minute (int):
|
199
|
-
Maximum number of tokens that can accumulate per minute.
|
200
|
-
available_request_capacity (int):
|
201
|
-
Current number of available request slots.
|
202
|
-
available_token_capacity (int):
|
203
|
-
Current number of available tokens.
|
204
|
-
|
205
|
-
Methods:
|
206
|
-
rate_limit_replenisher:
|
207
|
-
Coroutine to replenish rate limits over time.
|
208
|
-
calculate_num_token:
|
209
|
-
Method to calculate required tokens for a request.
|
210
|
-
"""
|
211
|
-
|
212
|
-
def __init__(self, max_requests_per_minute: int, max_tokens_per_minute: int) -> None:
|
213
|
-
"""
|
214
|
-
Initializes the RateLimiter with specified maximum request and token limits.
|
215
|
-
|
216
|
-
Parameters:
|
217
|
-
max_requests_per_minute (int): Maximum requests allowed per minute.
|
218
|
-
|
219
|
-
max_tokens_per_minute (int): Maximum tokens allowed to accumulate per minute.
|
220
|
-
|
221
|
-
Example:
|
222
|
-
>>> class MyRateLimiter(RateLimiter):
|
223
|
-
... async def rate_limit_replenisher(self) -> NoReturn:
|
224
|
-
... # Implementation for rate replenishment.
|
225
|
-
... def calculate_num_token(self, payload: Dict[str, Any], api_endpoint: str) -> int:
|
226
|
-
... # Implementation for token calculation.
|
227
|
-
...
|
228
|
-
>>> limiter = MyRateLimiter(100, 200)
|
229
|
-
"""
|
230
|
-
self.max_requests_per_minute = max_requests_per_minute
|
231
|
-
self.max_tokens_per_minute = max_tokens_per_minute
|
232
|
-
self.available_request_capacity = max_requests_per_minute
|
233
|
-
self.available_token_capacity = max_tokens_per_minute
|
234
|
-
|
235
|
-
@abstractmethod
|
236
|
-
async def rate_limit_replenisher(self) -> NoReturn:
|
237
|
-
"""
|
238
|
-
Asynchronously replenishes rate limit capacities.
|
239
|
-
|
240
|
-
This coroutine should be implemented to periodically restore `available_request_capacity`
|
241
|
-
and `available_token_capacity` according to specific rules defined in subclasses.
|
242
|
-
|
243
|
-
Example:
|
244
|
-
>>> class MyRateLimiter(RateLimiter):
|
245
|
-
... async def rate_limit_replenisher(self) -> NoReturn:
|
246
|
-
... while True:
|
247
|
-
... # Replenishment logic here
|
248
|
-
...
|
249
|
-
>>> limiter = MyRateLimiter(100, 200)
|
250
|
-
"""
|
251
|
-
|
252
|
-
...
|
253
|
-
|
254
|
-
@abstractmethod
|
255
|
-
def calculate_num_token(self, payload: Dict[str, Any], api_endpoint: str) -> int:
|
256
|
-
"""
|
257
|
-
Calculates required tokens for a request.
|
258
|
-
|
259
|
-
Subclasses should implement this method to determine the number of tokens needed based
|
260
|
-
on the request payload and target endpoint.
|
261
|
-
|
262
|
-
Parameters:
|
263
|
-
payload (Dict[str, Any]): Payload of the request.
|
264
|
-
|
265
|
-
api_endpoint (str): Target API endpoint for the request.
|
266
|
-
|
267
|
-
Returns:
|
268
|
-
int: Calculated number of tokens required for the request.
|
269
|
-
|
270
|
-
Example:
|
271
|
-
>>> class MyRateLimiter(RateLimiter):
|
272
|
-
... def calculate_num_token(self, payload: Dict[str, Any], api_endpoint: str) -> int:
|
273
|
-
... return len(payload.get('data', '')) // 10
|
274
|
-
...
|
275
|
-
>>> limiter = MyRateLimiter(100, 200)
|
276
|
-
>>> limiter.calculate_num_token({'data': '12345'}, 'api/send')
|
277
|
-
0
|
278
|
-
"""
|
279
|
-
|
280
|
-
...
|
281
|
-
|
282
|
-
|
lionagi/structure/structure.py
DELETED
@@ -1,160 +0,0 @@
|
|
1
|
-
from typing import TypeVar, Dict, Optional, Any, Type, Union, List
|
2
|
-
from pydantic import Field
|
3
|
-
from ..schema.base_schema import BaseNode
|
4
|
-
from .relationship import Relationship
|
5
|
-
|
6
|
-
T = TypeVar('T', bound='BaseNode')
|
7
|
-
R = TypeVar('R', bound='Relationship')
|
8
|
-
|
9
|
-
|
10
|
-
class Structure(BaseNode):
|
11
|
-
"""
|
12
|
-
Represents the structure of a graph consisting of nodes and relationships.
|
13
|
-
"""
|
14
|
-
nodes: Dict[str, T] = Field(default_factory=dict)
|
15
|
-
relationships: Dict[str, R] = Field(default_factory=dict)
|
16
|
-
node_relationships: Dict[str, Dict[str, Dict[str, str]]] = Field(default_factory=dict)
|
17
|
-
|
18
|
-
def add_node(self, node: T) -> None:
|
19
|
-
"""
|
20
|
-
Adds a node to the structure.
|
21
|
-
|
22
|
-
Args:
|
23
|
-
node (T): The node instance to be added.
|
24
|
-
"""
|
25
|
-
self.nodes[node.id_] = node
|
26
|
-
self.node_relationships[node.id_] = {'in': {}, 'out': {}}
|
27
|
-
|
28
|
-
def add_relationship(self, relationship: R) -> None:
|
29
|
-
"""
|
30
|
-
Adds a relationship to the structure.
|
31
|
-
|
32
|
-
Args:
|
33
|
-
relationship (R): The relationship instance to be added.
|
34
|
-
"""
|
35
|
-
id_, source_, target_ = (
|
36
|
-
relationship.id_, relationship.source_node_id, relationship.target_node_id
|
37
|
-
)
|
38
|
-
|
39
|
-
self.relationships.update({id_ : relationship})
|
40
|
-
self.node_relationships[source_]['out'].update({id_ : target_})
|
41
|
-
self.node_relationships[target_]['in'].update({id_ : source_})
|
42
|
-
|
43
|
-
# type can be dict or list
|
44
|
-
@staticmethod
|
45
|
-
def _typed_return(type: Type[Union[Dict, List]],
|
46
|
-
obj: Optional[Dict[str, Any]] = None
|
47
|
-
) -> Union[Dict[str, Any], List[Any]]:
|
48
|
-
"""
|
49
|
-
Returns the object in the specified type format.
|
50
|
-
|
51
|
-
Args:
|
52
|
-
type (Type[Union[Dict, List]]): The type to return the object as (dict or list).
|
53
|
-
|
54
|
-
obj (Optional[Dict[str, Any]]): The object to be converted.
|
55
|
-
|
56
|
-
Returns:
|
57
|
-
Union[Dict[str, Any], List[Any]]: The object in the specified type format.
|
58
|
-
"""
|
59
|
-
if type is list:
|
60
|
-
return list(obj.values())
|
61
|
-
return obj
|
62
|
-
|
63
|
-
def get_relationships(self, type: Type = dict) -> Union[Dict[str, R], List[R]]:
|
64
|
-
"""
|
65
|
-
Returns the relationships in the specified type format.
|
66
|
-
|
67
|
-
Args:
|
68
|
-
type (Type): The type to return the relationships as (dict or list).
|
69
|
-
|
70
|
-
Returns:
|
71
|
-
Union[Dict[str, R], List[R]]: The relationships in the specified type format.
|
72
|
-
"""
|
73
|
-
return self._typed_return(self.relationships, type=type)
|
74
|
-
|
75
|
-
def get_node_relationships(self, id_: str, in_out: str, type: Type = dict
|
76
|
-
) -> Union[Dict[str, str], List[str]]:
|
77
|
-
"""
|
78
|
-
Returns the relationships of a node in the specified type format.
|
79
|
-
|
80
|
-
Args:
|
81
|
-
id_ (str): The ID of the node.
|
82
|
-
|
83
|
-
in_out (str): 'in' for incoming relationships, 'out' for outgoing relationships.
|
84
|
-
|
85
|
-
type (Type): The type to return the relationships as (dict or list).
|
86
|
-
|
87
|
-
Returns:
|
88
|
-
Union[Dict[str, str], List[str]]: The relationships of the node in the specified type format.
|
89
|
-
"""
|
90
|
-
node_relationships = self.node_relationships[id_][in_out]
|
91
|
-
return self._typed_return(node_relationships, type=type)
|
92
|
-
|
93
|
-
def node_exist(self, node: Union[T, str]) -> bool:
|
94
|
-
"""
|
95
|
-
Checks if a node exists in the structure.
|
96
|
-
|
97
|
-
Args:
|
98
|
-
node (Union[T, str]): The node instance or node ID to check for existence.
|
99
|
-
|
100
|
-
Returns:
|
101
|
-
bool: True if the node exists, False otherwise.
|
102
|
-
"""
|
103
|
-
|
104
|
-
return node.id_ in self.nodes.keys()
|
105
|
-
|
106
|
-
def relationship_exist(self, relationship: R) -> bool:
|
107
|
-
"""
|
108
|
-
Checks if a relationship exists in the structure.
|
109
|
-
|
110
|
-
Args:
|
111
|
-
relationship (R): The relationship instance to check for existence.
|
112
|
-
|
113
|
-
Returns:
|
114
|
-
bool: True if the relationship exists, False otherwise.
|
115
|
-
"""
|
116
|
-
return relationship.id_ in self.relationships.keys()
|
117
|
-
|
118
|
-
def remove_node_relationships(self, relationship_dict: Dict[str, str], in_out: str) -> None:
|
119
|
-
"""
|
120
|
-
Removes relationships of a node from the structure.
|
121
|
-
|
122
|
-
Args:
|
123
|
-
relationship_dict (Dict[str, str]): A dictionary of relationship IDs to node IDs.
|
124
|
-
|
125
|
-
in_out (str): 'in' to remove incoming relationships, 'out' to remove outgoing relationships.
|
126
|
-
"""
|
127
|
-
for relationship_id, node_id in relationship_dict.items():
|
128
|
-
self.node_relationships[node_id][in_out].pop(relationship_id)
|
129
|
-
self.relationships.pop(relationship_id)
|
130
|
-
|
131
|
-
def remove_node(self, node: Union[T, str]) -> None:
|
132
|
-
"""
|
133
|
-
Removes a node and its associated relationships from the structure.
|
134
|
-
|
135
|
-
Args:
|
136
|
-
node (Union[T, str]): The node instance or node ID to be removed.
|
137
|
-
"""
|
138
|
-
node_id = node if isinstance(node, str) else node.id_
|
139
|
-
out_ = self.get_node_relationships(node_id, 'out')
|
140
|
-
in_ = self.get_node_relationships(node_id, 'in')
|
141
|
-
|
142
|
-
self.remove_node_relationships(out_, 'in')
|
143
|
-
self.remove_node_relationships(in_, 'out')
|
144
|
-
self.node_relationships.pop(node_id)
|
145
|
-
|
146
|
-
def remove_relationship(self, relationship: R) -> None:
|
147
|
-
"""
|
148
|
-
Removes a relationship from the structure.
|
149
|
-
|
150
|
-
Args:
|
151
|
-
relationship (R): The relationship instance to be removed.
|
152
|
-
"""
|
153
|
-
id_, source_, target_ = (relationship.id_,
|
154
|
-
relationship.source_node_id,
|
155
|
-
relationship.target_node_id)
|
156
|
-
|
157
|
-
self.node_relationships[source_]['out'].pop(id_)
|
158
|
-
self.node_relationships[target_]['in'].pop(id_)
|
159
|
-
self.relationships.pop(id_)
|
160
|
-
|
lionagi/tools/coder.py
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
# TODO
|
lionagi/tools/sandbox.py
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
# TODO
|
lionagi/utils/tool_util.py
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
import inspect
|
2
|
-
from ..schema.base_tool import Tool
|
3
|
-
|
4
|
-
|
5
|
-
def extract_docstring_details(func):
|
6
|
-
"""
|
7
|
-
Extracts detailed descriptions for each parameter and the function from the docstring.
|
8
|
-
|
9
|
-
Parameters:
|
10
|
-
func (function): The function to extract details from.
|
11
|
-
|
12
|
-
Returns:
|
13
|
-
Tuple[str, dict]: Function description and a dictionary of parameter descriptions.
|
14
|
-
"""
|
15
|
-
docstring = inspect.getdoc(func)
|
16
|
-
if not docstring:
|
17
|
-
return "No description available.", {}
|
18
|
-
|
19
|
-
# Splitting the docstring into lines
|
20
|
-
lines = docstring.split('\n')
|
21
|
-
|
22
|
-
# Extracting the function description
|
23
|
-
func_description = lines[0].strip()
|
24
|
-
|
25
|
-
# Extracting parameter descriptions
|
26
|
-
param_descriptions = {}
|
27
|
-
current_param = None
|
28
|
-
for line in lines[1:]:
|
29
|
-
line = line.strip()
|
30
|
-
if line.startswith(':param'):
|
31
|
-
_, param, desc = line.split(' ', 2)
|
32
|
-
current_param = param.strip(':')
|
33
|
-
param_descriptions[current_param] = desc
|
34
|
-
elif current_param and line:
|
35
|
-
# Continue the description of the current parameter
|
36
|
-
param_descriptions[current_param] += ' ' + line
|
37
|
-
|
38
|
-
return func_description, param_descriptions
|
39
|
-
|
40
|
-
def func_to_schema(func):
|
41
|
-
"""
|
42
|
-
Generates a schema description for a given function, using typing hints and docstrings.
|
43
|
-
The schema includes the function's name, description, and parameters.
|
44
|
-
|
45
|
-
Parameters:
|
46
|
-
func (function): The function to generate a schema for.
|
47
|
-
|
48
|
-
Returns:
|
49
|
-
dict: A schema describing the function.
|
50
|
-
"""
|
51
|
-
# Extracting function name and docstring details
|
52
|
-
func_name = func.__name__
|
53
|
-
func_description, param_descriptions = extract_docstring_details(func)
|
54
|
-
|
55
|
-
# Extracting parameters with typing hints
|
56
|
-
sig = inspect.signature(func)
|
57
|
-
parameters = {
|
58
|
-
"type": "object",
|
59
|
-
"properties": {},
|
60
|
-
"required": [],
|
61
|
-
}
|
62
|
-
|
63
|
-
for name, param in sig.parameters.items():
|
64
|
-
# Default type to string and update if type hint is available
|
65
|
-
param_type = "string"
|
66
|
-
if param.annotation is not inspect.Parameter.empty:
|
67
|
-
param_type = param.annotation.__name__
|
68
|
-
|
69
|
-
# Extract parameter description from docstring, if available
|
70
|
-
param_description = param_descriptions.get(name, "No description available.")
|
71
|
-
|
72
|
-
# Assuming all parameters are required for simplicity
|
73
|
-
parameters["required"].append(name)
|
74
|
-
parameters["properties"][name] = {
|
75
|
-
"type": param_type,
|
76
|
-
"description": param_description,
|
77
|
-
}
|
78
|
-
|
79
|
-
# Constructing the schema
|
80
|
-
schema = {
|
81
|
-
"type": "function",
|
82
|
-
"function": {
|
83
|
-
"name": func_name,
|
84
|
-
"description": func_description,
|
85
|
-
"parameters": parameters,
|
86
|
-
}
|
87
|
-
}
|
88
|
-
return schema
|
89
|
-
|
90
|
-
def func_to_tool(func_, schema, parser=None):
|
91
|
-
# schema = func_to_schema(func_)
|
92
|
-
return Tool(func=func_, parser=parser, schema_=schema)
|
lionagi/utils/type_util.py
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
import re
|
2
|
-
from typing import Optional, Union, Iterable, List, Any, Type
|
3
|
-
|
4
|
-
from .flat_util import flatten_list
|
5
|
-
|
6
|
-
|
7
|
-
def str_to_num(input_: str,
|
8
|
-
upper_bound: Optional[Union[int, float]] = None,
|
9
|
-
lower_bound: Optional[Union[int, float]] = None,
|
10
|
-
num_type: Type[Union[int, float]] = int,
|
11
|
-
precision: Optional[int] = None) -> Union[int, float]:
|
12
|
-
"""
|
13
|
-
Converts the first number in the input string to the specified numeric type.
|
14
|
-
|
15
|
-
Parameters:
|
16
|
-
input_ (str): The input string to extract the number from.
|
17
|
-
|
18
|
-
upper_bound (Optional[Union[int, float]]): The upper bound for the number. Defaults to None.
|
19
|
-
|
20
|
-
lower_bound (Optional[Union[int, float]]): The lower bound for the number. Defaults to None.
|
21
|
-
|
22
|
-
num_type (Type[Union[int, float]]): The type of the number to return (int or float). Defaults to int.
|
23
|
-
|
24
|
-
precision (Optional[int]): The precision for the floating-point number. Defaults to None.
|
25
|
-
|
26
|
-
Returns:
|
27
|
-
Union[int, float]: The converted number.
|
28
|
-
|
29
|
-
Raises:
|
30
|
-
ValueError: If no numeric values are found in the string or if there are conversion errors.
|
31
|
-
"""
|
32
|
-
numbers = re.findall(r'-?\d+\.?\d*', input_)
|
33
|
-
if not numbers:
|
34
|
-
raise ValueError(f"No numeric values found in the string: {input_}")
|
35
|
-
|
36
|
-
try:
|
37
|
-
numbers = numbers[0]
|
38
|
-
if num_type is int:
|
39
|
-
numbers = int(float(numbers))
|
40
|
-
elif num_type is float:
|
41
|
-
numbers = round(float(numbers), precision) if precision is not None else float(numbers)
|
42
|
-
else:
|
43
|
-
raise ValueError(f"Invalid number type: {num_type}")
|
44
|
-
if upper_bound is not None and numbers > upper_bound:
|
45
|
-
raise ValueError(f"Number {numbers} is greater than the upper bound of {upper_bound}.")
|
46
|
-
if lower_bound is not None and numbers < lower_bound:
|
47
|
-
raise ValueError(f"Number {numbers} is less than the lower bound of {lower_bound}.")
|
48
|
-
return numbers
|
49
|
-
|
50
|
-
except ValueError as e:
|
51
|
-
raise ValueError(f"Error converting string to number: {e}")
|
52
|
-
|
53
|
-
def to_list(input_: Any, flatten: bool = True, dropna: bool = False) -> List[Any]:
|
54
|
-
"""
|
55
|
-
Converts the input to a list, optionally flattening it and dropping None values.
|
56
|
-
|
57
|
-
Parameters:
|
58
|
-
input_ (Any): The input to convert to a list.
|
59
|
-
|
60
|
-
flatten (bool): Whether to flatten the input if it is a nested list. Defaults to True.
|
61
|
-
|
62
|
-
dropna (bool): Whether to drop None values from the list. Defaults to False.
|
63
|
-
|
64
|
-
Returns:
|
65
|
-
List[Any]: The input converted to a list.
|
66
|
-
|
67
|
-
Raises:
|
68
|
-
ValueError: If the input cannot be converted to a list.
|
69
|
-
"""
|
70
|
-
if isinstance(input_, list) and flatten:
|
71
|
-
input_ = flatten_list(input_)
|
72
|
-
if dropna:
|
73
|
-
input_ = [i for i in input_ if i is not None]
|
74
|
-
elif isinstance(input_, Iterable) and not isinstance(input_, (str, dict)):
|
75
|
-
try:
|
76
|
-
input_ = list(input_)
|
77
|
-
except:
|
78
|
-
raise ValueError("Input cannot be converted to a list.")
|
79
|
-
else:
|
80
|
-
input_ = [input_]
|
81
|
-
return input_
|