lionagi 0.12.2__py3-none-any.whl → 0.12.4__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/config.py +123 -0
- lionagi/fields/file.py +1 -1
- lionagi/fields/reason.py +1 -1
- lionagi/libs/file/concat.py +1 -6
- lionagi/libs/file/concat_files.py +1 -5
- lionagi/libs/file/save.py +1 -1
- lionagi/libs/package/imports.py +8 -177
- lionagi/libs/parse.py +30 -0
- lionagi/libs/schema/load_pydantic_model_from_schema.py +259 -0
- lionagi/libs/token_transform/perplexity.py +2 -4
- lionagi/libs/token_transform/synthlang_/resources/frameworks/framework_options.json +46 -46
- lionagi/libs/token_transform/synthlang_/translate_to_synthlang.py +1 -1
- lionagi/operations/chat/chat.py +2 -2
- lionagi/operations/communicate/communicate.py +20 -5
- lionagi/operations/parse/parse.py +131 -43
- lionagi/protocols/generic/log.py +1 -2
- lionagi/protocols/generic/pile.py +18 -4
- lionagi/protocols/messages/assistant_response.py +20 -1
- lionagi/protocols/messages/templates/README.md +6 -10
- lionagi/service/connections/__init__.py +15 -0
- lionagi/service/connections/api_calling.py +230 -0
- lionagi/service/connections/endpoint.py +410 -0
- lionagi/service/connections/endpoint_config.py +137 -0
- lionagi/service/connections/header_factory.py +56 -0
- lionagi/service/connections/match_endpoint.py +49 -0
- lionagi/service/connections/providers/__init__.py +3 -0
- lionagi/service/connections/providers/anthropic_.py +87 -0
- lionagi/service/connections/providers/exa_.py +33 -0
- lionagi/service/connections/providers/oai_.py +166 -0
- lionagi/service/connections/providers/ollama_.py +122 -0
- lionagi/service/connections/providers/perplexity_.py +29 -0
- lionagi/service/imodel.py +36 -144
- lionagi/service/manager.py +1 -7
- lionagi/service/{endpoints/rate_limited_processor.py → rate_limited_processor.py} +4 -2
- lionagi/service/resilience.py +545 -0
- lionagi/service/third_party/README.md +71 -0
- lionagi/service/third_party/__init__.py +0 -0
- lionagi/service/third_party/anthropic_models.py +159 -0
- lionagi/service/third_party/exa_models.py +165 -0
- lionagi/service/third_party/openai_models.py +18241 -0
- lionagi/service/third_party/pplx_models.py +156 -0
- lionagi/service/types.py +5 -4
- lionagi/session/branch.py +12 -7
- lionagi/tools/file/reader.py +1 -1
- lionagi/tools/memory/tools.py +497 -0
- lionagi/utils.py +921 -123
- lionagi/version.py +1 -1
- {lionagi-0.12.2.dist-info → lionagi-0.12.4.dist-info}/METADATA +33 -16
- {lionagi-0.12.2.dist-info → lionagi-0.12.4.dist-info}/RECORD +53 -63
- lionagi/libs/file/create_path.py +0 -80
- lionagi/libs/file/file_util.py +0 -358
- lionagi/libs/parse/__init__.py +0 -3
- lionagi/libs/parse/fuzzy_parse_json.py +0 -117
- lionagi/libs/parse/to_dict.py +0 -336
- lionagi/libs/parse/to_json.py +0 -61
- lionagi/libs/parse/to_num.py +0 -378
- lionagi/libs/parse/to_xml.py +0 -57
- lionagi/libs/parse/xml_parser.py +0 -148
- lionagi/libs/schema/breakdown_pydantic_annotation.py +0 -48
- lionagi/service/endpoints/__init__.py +0 -3
- lionagi/service/endpoints/base.py +0 -706
- lionagi/service/endpoints/chat_completion.py +0 -116
- lionagi/service/endpoints/match_endpoint.py +0 -72
- lionagi/service/providers/__init__.py +0 -3
- lionagi/service/providers/anthropic_/__init__.py +0 -3
- lionagi/service/providers/anthropic_/messages.py +0 -99
- lionagi/service/providers/exa_/models.py +0 -3
- lionagi/service/providers/exa_/search.py +0 -80
- lionagi/service/providers/exa_/types.py +0 -7
- lionagi/service/providers/groq_/__init__.py +0 -3
- lionagi/service/providers/groq_/chat_completions.py +0 -56
- lionagi/service/providers/ollama_/__init__.py +0 -3
- lionagi/service/providers/ollama_/chat_completions.py +0 -134
- lionagi/service/providers/openai_/__init__.py +0 -3
- lionagi/service/providers/openai_/chat_completions.py +0 -101
- lionagi/service/providers/openai_/spec.py +0 -14
- lionagi/service/providers/openrouter_/__init__.py +0 -3
- lionagi/service/providers/openrouter_/chat_completions.py +0 -62
- lionagi/service/providers/perplexity_/__init__.py +0 -3
- lionagi/service/providers/perplexity_/chat_completions.py +0 -44
- lionagi/service/providers/perplexity_/models.py +0 -5
- lionagi/service/providers/types.py +0 -17
- /lionagi/{service/providers/exa_/__init__.py → py.typed} +0 -0
- /lionagi/service/{endpoints/token_calculator.py → token_calculator.py} +0 -0
- {lionagi-0.12.2.dist-info → lionagi-0.12.4.dist-info}/WHEEL +0 -0
- {lionagi-0.12.2.dist-info → lionagi-0.12.4.dist-info}/licenses/LICENSE +0 -0
lionagi/service/imodel.py
CHANGED
@@ -3,17 +3,17 @@
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
5
|
import asyncio
|
6
|
-
import os
|
7
6
|
from collections.abc import AsyncGenerator, Callable
|
8
7
|
|
9
8
|
from pydantic import BaseModel
|
10
9
|
|
11
10
|
from lionagi.protocols.generic.event import EventStatus
|
12
|
-
from lionagi.utils import is_coro_func
|
11
|
+
from lionagi.utils import is_coro_func
|
13
12
|
|
14
|
-
from .
|
15
|
-
from .
|
16
|
-
from .
|
13
|
+
from .connections.api_calling import APICalling
|
14
|
+
from .connections.endpoint import Endpoint
|
15
|
+
from .connections.match_endpoint import match_endpoint
|
16
|
+
from .rate_limited_processor import RateLimitedAPIExecutor
|
17
17
|
|
18
18
|
|
19
19
|
class iModel:
|
@@ -25,15 +25,9 @@ class iModel:
|
|
25
25
|
handle queuing and throttling requests.
|
26
26
|
|
27
27
|
Attributes:
|
28
|
-
endpoint (
|
28
|
+
endpoint (Endpoint):
|
29
29
|
The chosen endpoint object (constructed via `match_endpoint` if
|
30
30
|
none is provided).
|
31
|
-
should_invoke_endpoint (bool):
|
32
|
-
If True, the endpoint is called for real. If False, calls might
|
33
|
-
be mocked or cached.
|
34
|
-
kwargs (dict):
|
35
|
-
Any additional keyword arguments passed to initialize and
|
36
|
-
configure the iModel (e.g., `model`, `api_key`).
|
37
31
|
executor (RateLimitedAPIExecutor):
|
38
32
|
The rate-limited executor that queues and runs API calls in a
|
39
33
|
controlled fashion.
|
@@ -43,18 +37,15 @@ class iModel:
|
|
43
37
|
self,
|
44
38
|
provider: str = None,
|
45
39
|
base_url: str = None,
|
46
|
-
endpoint: str |
|
47
|
-
endpoint_params: list[str] | None = None,
|
40
|
+
endpoint: str | Endpoint = "chat",
|
48
41
|
api_key: str = None,
|
49
42
|
queue_capacity: int = 100,
|
50
43
|
capacity_refresh_time: float = 60,
|
51
44
|
interval: float | None = None,
|
52
45
|
limit_requests: int = None,
|
53
46
|
limit_tokens: int = None,
|
54
|
-
invoke_with_endpoint: bool = None,
|
55
47
|
concurrency_limit: int | None = None,
|
56
48
|
streaming_process_func: Callable = None,
|
57
|
-
requires_api_key: bool = True,
|
58
49
|
**kwargs,
|
59
50
|
) -> None:
|
60
51
|
"""Initializes the iModel instance.
|
@@ -64,9 +55,9 @@ class iModel:
|
|
64
55
|
Name of the provider (e.g., 'openai', 'anthropic').
|
65
56
|
base_url (str, optional):
|
66
57
|
Base URL for the API (if a custom endpoint is needed).
|
67
|
-
endpoint (str |
|
58
|
+
endpoint (str | Endpoint, optional):
|
68
59
|
Either a string representing the endpoint type (e.g., 'chat')
|
69
|
-
or an `
|
60
|
+
or an `Endpoint` instance.
|
70
61
|
endpoint_params (list[str] | None, optional):
|
71
62
|
Additional parameters for the endpoint (e.g., 'v1' or other).
|
72
63
|
api_key (str, optional):
|
@@ -85,9 +76,6 @@ class iModel:
|
|
85
76
|
Maximum number of requests allowed per cycle, if any.
|
86
77
|
limit_tokens (int | None, optional):
|
87
78
|
Maximum number of tokens allowed per cycle, if any.
|
88
|
-
invoke_with_endpoint (bool, optional):
|
89
|
-
If True, the endpoint is actually invoked. If False,
|
90
|
-
calls might be mocked or cached.
|
91
79
|
concurrency_limit (int | None, optional):
|
92
80
|
Maximum number of streaming concurrent requests allowed.
|
93
81
|
only applies to streaming requests.
|
@@ -105,56 +93,22 @@ class iModel:
|
|
105
93
|
else:
|
106
94
|
raise ValueError("Provider must be provided")
|
107
95
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
api_key = "OPENAI_API_KEY"
|
113
|
-
case "anthropic":
|
114
|
-
api_key = "ANTHROPIC_API_KEY"
|
115
|
-
case "openrouter":
|
116
|
-
api_key = "OPENROUTER_API_KEY"
|
117
|
-
case "perplexity":
|
118
|
-
api_key = "PERPLEXITY_API_KEY"
|
119
|
-
case "groq":
|
120
|
-
api_key = "GROQ_API_KEY"
|
121
|
-
case "exa":
|
122
|
-
api_key = "EXA_API_KEY"
|
123
|
-
case "ollama":
|
124
|
-
api_key = "ollama"
|
125
|
-
case "":
|
126
|
-
if requires_api_key:
|
127
|
-
raise ValueError("API key must be provided")
|
128
|
-
case _:
|
129
|
-
api_key = f"{provider.upper()}_API_KEY"
|
130
|
-
|
131
|
-
if os.getenv(api_key, None) is not None:
|
132
|
-
self.api_key_scheme = api_key
|
133
|
-
api_key = os.getenv(api_key)
|
134
|
-
|
135
|
-
kwargs["api_key"] = api_key
|
136
|
-
if isinstance(endpoint, EndPoint):
|
96
|
+
# Pass api_key to endpoint if provided
|
97
|
+
if api_key is not None:
|
98
|
+
kwargs["api_key"] = api_key
|
99
|
+
if isinstance(endpoint, Endpoint):
|
137
100
|
self.endpoint = endpoint
|
138
101
|
else:
|
139
102
|
self.endpoint = match_endpoint(
|
140
103
|
provider=provider,
|
141
|
-
base_url=base_url,
|
142
104
|
endpoint=endpoint,
|
143
|
-
|
105
|
+
**kwargs,
|
144
106
|
)
|
145
107
|
if provider:
|
146
108
|
self.endpoint.config.provider = provider
|
147
109
|
if base_url:
|
148
110
|
self.endpoint.config.base_url = base_url
|
149
111
|
|
150
|
-
if (
|
151
|
-
invoke_with_endpoint is None
|
152
|
-
and self.endpoint.config.invoke_with_endpoint is True
|
153
|
-
):
|
154
|
-
invoke_with_endpoint = True
|
155
|
-
|
156
|
-
self.should_invoke_endpoint = invoke_with_endpoint or False
|
157
|
-
self.kwargs = kwargs
|
158
112
|
self.executor = RateLimitedAPIExecutor(
|
159
113
|
queue_capacity=queue_capacity,
|
160
114
|
capacity_refresh_time=capacity_refresh_time,
|
@@ -163,12 +117,8 @@ class iModel:
|
|
163
117
|
limit_tokens=limit_tokens,
|
164
118
|
concurrency_limit=concurrency_limit,
|
165
119
|
)
|
166
|
-
|
167
|
-
|
168
|
-
):
|
169
|
-
self.streaming_process_func = self.endpoint.process_chunk
|
170
|
-
else:
|
171
|
-
self.streaming_process_func = streaming_process_func
|
120
|
+
# Use provided streaming_process_func or default to None
|
121
|
+
self.streaming_process_func = streaming_process_func
|
172
122
|
|
173
123
|
def create_api_calling(
|
174
124
|
self, include_token_usage_to_model: bool = False, **kwargs
|
@@ -177,22 +127,24 @@ class iModel:
|
|
177
127
|
|
178
128
|
Args:
|
179
129
|
**kwargs:
|
180
|
-
Additional arguments used to generate the payload
|
181
|
-
with self.kwargs).
|
130
|
+
Additional arguments used to generate the payload.
|
182
131
|
|
183
132
|
Returns:
|
184
133
|
APICalling:
|
185
134
|
An `APICalling` instance with the constructed payload,
|
186
135
|
headers, and the selected endpoint.
|
187
136
|
"""
|
188
|
-
|
189
|
-
payload = self.endpoint.create_payload(
|
137
|
+
# The new Endpoint.create_payload returns (payload, headers)
|
138
|
+
payload, headers = self.endpoint.create_payload(request=kwargs)
|
139
|
+
|
140
|
+
# Extract cache_control if provided
|
141
|
+
cache_control = kwargs.pop("cache_control", False)
|
142
|
+
|
190
143
|
return APICalling(
|
191
|
-
payload=payload
|
192
|
-
headers=
|
144
|
+
payload=payload,
|
145
|
+
headers=headers,
|
193
146
|
endpoint=self.endpoint,
|
194
|
-
|
195
|
-
should_invoke_endpoint=self.should_invoke_endpoint,
|
147
|
+
cache_control=cache_control,
|
196
148
|
include_token_usage_to_model=include_token_usage_to_model,
|
197
149
|
)
|
198
150
|
|
@@ -320,16 +272,6 @@ class iModel:
|
|
320
272
|
return self.endpoint.allowed_roles
|
321
273
|
return {"system", "user", "assistant"}
|
322
274
|
|
323
|
-
@property
|
324
|
-
def sequential_exchange(self) -> bool:
|
325
|
-
"""bool: Indicates whether requests must occur in a strict sequence.
|
326
|
-
|
327
|
-
Returns:
|
328
|
-
True if the endpoint requires sequential handling of
|
329
|
-
messages; False otherwise.
|
330
|
-
"""
|
331
|
-
return self.endpoint.sequential_exchange
|
332
|
-
|
333
275
|
@property
|
334
276
|
def model_name(self) -> str:
|
335
277
|
"""str: The name of the model used by the endpoint.
|
@@ -337,7 +279,7 @@ class iModel:
|
|
337
279
|
Returns:
|
338
280
|
The model name if available; otherwise, an empty string.
|
339
281
|
"""
|
340
|
-
return self.kwargs.get("model", "")
|
282
|
+
return self.endpoint.config.kwargs.get("model", "")
|
341
283
|
|
342
284
|
@property
|
343
285
|
def request_options(self) -> type[BaseModel] | None:
|
@@ -349,73 +291,23 @@ class iModel:
|
|
349
291
|
return self.endpoint.request_options
|
350
292
|
|
351
293
|
def to_dict(self):
|
352
|
-
kwargs = self.kwargs
|
353
|
-
if "kwargs" in self.kwargs:
|
354
|
-
kwargs = self.kwargs["kwargs"]
|
355
|
-
|
356
294
|
return {
|
357
|
-
"
|
358
|
-
"endpoint": self.endpoint.config.model_dump_json(),
|
359
|
-
"api_key": (
|
360
|
-
self.api_key_scheme
|
361
|
-
if hasattr(self, "api_key_scheme")
|
362
|
-
else None
|
363
|
-
),
|
295
|
+
"endpoint": self.endpoint.to_dict(),
|
364
296
|
"processor_config": self.executor.config,
|
365
|
-
"invoke_with_endpoint": self.should_invoke_endpoint,
|
366
|
-
**{k: v for k, v in kwargs.items() if k != "api_key"},
|
367
297
|
}
|
368
298
|
|
369
299
|
@classmethod
|
370
300
|
def from_dict(cls, data: dict):
|
371
|
-
|
372
|
-
base_url = data.pop("base_url", None)
|
373
|
-
api_key = data.pop("api_key", None)
|
374
|
-
|
375
|
-
processor_config = data.pop("processor_config", {})
|
376
|
-
endpoint_config_params = data.pop("endpoint", {})
|
377
|
-
endpoint_config_params = to_dict(endpoint_config_params)
|
301
|
+
endpoint = Endpoint.from_dict(data.get("endpoint", {}))
|
378
302
|
|
379
|
-
|
380
|
-
|
303
|
+
e1 = match_endpoint(
|
304
|
+
provider=endpoint.config.provider,
|
305
|
+
endpoint=endpoint.config.endpoint,
|
381
306
|
)
|
382
|
-
match_params = {}
|
383
307
|
|
384
|
-
|
385
|
-
|
386
|
-
match_params[i] = endpoint_config_params.pop(i)
|
387
|
-
endpoint = match_endpoint(**match_params)
|
388
|
-
endpoint.update_config(**endpoint_config_params)
|
308
|
+
e1.config = endpoint.config
|
309
|
+
|
389
310
|
return cls(
|
390
|
-
|
391
|
-
|
392
|
-
endpoint=endpoint,
|
393
|
-
api_key=api_key,
|
394
|
-
**data,
|
395
|
-
**processor_config,
|
311
|
+
endpoint=e1,
|
312
|
+
**data.get("processor_config", {}),
|
396
313
|
)
|
397
|
-
|
398
|
-
async def compress_text(
|
399
|
-
self,
|
400
|
-
text: str,
|
401
|
-
system: str = None,
|
402
|
-
compression_ratio: float = 0.2,
|
403
|
-
n_samples: int = 5,
|
404
|
-
max_tokens_per_sample=80,
|
405
|
-
verbose=True,
|
406
|
-
initial_text=None,
|
407
|
-
cumulative=False,
|
408
|
-
split_kwargs=None,
|
409
|
-
min_pplx=None,
|
410
|
-
**kwargs,
|
411
|
-
) -> str:
|
412
|
-
"""
|
413
|
-
Convenience function that instantiates LLMCompressor and compresses text.
|
414
|
-
"""
|
415
|
-
from lionagi.libs.token_transform.perplexity import compress_text
|
416
|
-
|
417
|
-
params = {
|
418
|
-
k: v for k, v in locals().items() if k not in ("self", "kwargs")
|
419
|
-
}
|
420
|
-
params.update(kwargs)
|
421
|
-
return await compress_text(**params)
|
lionagi/service/manager.py
CHANGED
@@ -5,7 +5,6 @@
|
|
5
5
|
from lionagi.protocols._concepts import Manager
|
6
6
|
from lionagi.utils import is_same_dtype
|
7
7
|
|
8
|
-
from .endpoints.chat_completion import ChatCompletionEndPoint
|
9
8
|
from .imodel import iModel
|
10
9
|
|
11
10
|
|
@@ -34,12 +33,7 @@ class iModelManager(Manager):
|
|
34
33
|
return self.registry.get("parse", None)
|
35
34
|
|
36
35
|
def register_imodel(self, name: str, model: iModel):
|
37
|
-
if isinstance(model
|
38
|
-
if name != "parse":
|
39
|
-
self.registry["chat"] = model
|
40
|
-
else:
|
41
|
-
self.registry["parse"] = model
|
42
|
-
elif isinstance(model, iModel):
|
36
|
+
if isinstance(model, iModel):
|
43
37
|
self.registry[name] = model
|
44
38
|
else:
|
45
39
|
raise TypeError("Input model is not an instance of iModel")
|
@@ -9,7 +9,7 @@ from typing_extensions import Self, override
|
|
9
9
|
|
10
10
|
from lionagi.protocols.types import Executor, Processor
|
11
11
|
|
12
|
-
from .
|
12
|
+
from .connections.api_calling import APICalling
|
13
13
|
|
14
14
|
__all__ = (
|
15
15
|
"RateLimitedAPIProcessor",
|
@@ -98,7 +98,9 @@ class RateLimitedAPIProcessor(Processor):
|
|
98
98
|
return self
|
99
99
|
|
100
100
|
@override
|
101
|
-
async def request_permission(
|
101
|
+
async def request_permission(
|
102
|
+
self, required_tokens: int = None, **kwargs
|
103
|
+
) -> bool:
|
102
104
|
async with self._lock:
|
103
105
|
if self.limit_requests is None and self.limit_tokens is None:
|
104
106
|
if self.queue.qsize() < self.queue_capacity:
|