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.
Files changed (86) hide show
  1. lionagi/config.py +123 -0
  2. lionagi/fields/file.py +1 -1
  3. lionagi/fields/reason.py +1 -1
  4. lionagi/libs/file/concat.py +1 -6
  5. lionagi/libs/file/concat_files.py +1 -5
  6. lionagi/libs/file/save.py +1 -1
  7. lionagi/libs/package/imports.py +8 -177
  8. lionagi/libs/parse.py +30 -0
  9. lionagi/libs/schema/load_pydantic_model_from_schema.py +259 -0
  10. lionagi/libs/token_transform/perplexity.py +2 -4
  11. lionagi/libs/token_transform/synthlang_/resources/frameworks/framework_options.json +46 -46
  12. lionagi/libs/token_transform/synthlang_/translate_to_synthlang.py +1 -1
  13. lionagi/operations/chat/chat.py +2 -2
  14. lionagi/operations/communicate/communicate.py +20 -5
  15. lionagi/operations/parse/parse.py +131 -43
  16. lionagi/protocols/generic/log.py +1 -2
  17. lionagi/protocols/generic/pile.py +18 -4
  18. lionagi/protocols/messages/assistant_response.py +20 -1
  19. lionagi/protocols/messages/templates/README.md +6 -10
  20. lionagi/service/connections/__init__.py +15 -0
  21. lionagi/service/connections/api_calling.py +230 -0
  22. lionagi/service/connections/endpoint.py +410 -0
  23. lionagi/service/connections/endpoint_config.py +137 -0
  24. lionagi/service/connections/header_factory.py +56 -0
  25. lionagi/service/connections/match_endpoint.py +49 -0
  26. lionagi/service/connections/providers/__init__.py +3 -0
  27. lionagi/service/connections/providers/anthropic_.py +87 -0
  28. lionagi/service/connections/providers/exa_.py +33 -0
  29. lionagi/service/connections/providers/oai_.py +166 -0
  30. lionagi/service/connections/providers/ollama_.py +122 -0
  31. lionagi/service/connections/providers/perplexity_.py +29 -0
  32. lionagi/service/imodel.py +36 -144
  33. lionagi/service/manager.py +1 -7
  34. lionagi/service/{endpoints/rate_limited_processor.py → rate_limited_processor.py} +4 -2
  35. lionagi/service/resilience.py +545 -0
  36. lionagi/service/third_party/README.md +71 -0
  37. lionagi/service/third_party/__init__.py +0 -0
  38. lionagi/service/third_party/anthropic_models.py +159 -0
  39. lionagi/service/third_party/exa_models.py +165 -0
  40. lionagi/service/third_party/openai_models.py +18241 -0
  41. lionagi/service/third_party/pplx_models.py +156 -0
  42. lionagi/service/types.py +5 -4
  43. lionagi/session/branch.py +12 -7
  44. lionagi/tools/file/reader.py +1 -1
  45. lionagi/tools/memory/tools.py +497 -0
  46. lionagi/utils.py +921 -123
  47. lionagi/version.py +1 -1
  48. {lionagi-0.12.2.dist-info → lionagi-0.12.4.dist-info}/METADATA +33 -16
  49. {lionagi-0.12.2.dist-info → lionagi-0.12.4.dist-info}/RECORD +53 -63
  50. lionagi/libs/file/create_path.py +0 -80
  51. lionagi/libs/file/file_util.py +0 -358
  52. lionagi/libs/parse/__init__.py +0 -3
  53. lionagi/libs/parse/fuzzy_parse_json.py +0 -117
  54. lionagi/libs/parse/to_dict.py +0 -336
  55. lionagi/libs/parse/to_json.py +0 -61
  56. lionagi/libs/parse/to_num.py +0 -378
  57. lionagi/libs/parse/to_xml.py +0 -57
  58. lionagi/libs/parse/xml_parser.py +0 -148
  59. lionagi/libs/schema/breakdown_pydantic_annotation.py +0 -48
  60. lionagi/service/endpoints/__init__.py +0 -3
  61. lionagi/service/endpoints/base.py +0 -706
  62. lionagi/service/endpoints/chat_completion.py +0 -116
  63. lionagi/service/endpoints/match_endpoint.py +0 -72
  64. lionagi/service/providers/__init__.py +0 -3
  65. lionagi/service/providers/anthropic_/__init__.py +0 -3
  66. lionagi/service/providers/anthropic_/messages.py +0 -99
  67. lionagi/service/providers/exa_/models.py +0 -3
  68. lionagi/service/providers/exa_/search.py +0 -80
  69. lionagi/service/providers/exa_/types.py +0 -7
  70. lionagi/service/providers/groq_/__init__.py +0 -3
  71. lionagi/service/providers/groq_/chat_completions.py +0 -56
  72. lionagi/service/providers/ollama_/__init__.py +0 -3
  73. lionagi/service/providers/ollama_/chat_completions.py +0 -134
  74. lionagi/service/providers/openai_/__init__.py +0 -3
  75. lionagi/service/providers/openai_/chat_completions.py +0 -101
  76. lionagi/service/providers/openai_/spec.py +0 -14
  77. lionagi/service/providers/openrouter_/__init__.py +0 -3
  78. lionagi/service/providers/openrouter_/chat_completions.py +0 -62
  79. lionagi/service/providers/perplexity_/__init__.py +0 -3
  80. lionagi/service/providers/perplexity_/chat_completions.py +0 -44
  81. lionagi/service/providers/perplexity_/models.py +0 -5
  82. lionagi/service/providers/types.py +0 -17
  83. /lionagi/{service/providers/exa_/__init__.py → py.typed} +0 -0
  84. /lionagi/service/{endpoints/token_calculator.py → token_calculator.py} +0 -0
  85. {lionagi-0.12.2.dist-info → lionagi-0.12.4.dist-info}/WHEEL +0 -0
  86. {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, to_dict
11
+ from lionagi.utils import is_coro_func
13
12
 
14
- from .endpoints.base import APICalling, EndPoint, EndpointConfig
15
- from .endpoints.match_endpoint import match_endpoint
16
- from .endpoints.rate_limited_processor import RateLimitedAPIExecutor
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 (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 | EndPoint = "chat",
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 | EndPoint, optional):
58
+ endpoint (str | Endpoint, optional):
68
59
  Either a string representing the endpoint type (e.g., 'chat')
69
- or an `EndPoint` instance.
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
- if api_key is None:
109
- provider = str(provider or "").strip().lower()
110
- match provider:
111
- case "openai":
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
- endpoint_params=endpoint_params,
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
- if not streaming_process_func and hasattr(
167
- self.endpoint, "process_chunk"
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 (merged
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
- kwargs.update(self.kwargs)
189
- payload = self.endpoint.create_payload(**kwargs)
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["payload"],
192
- headers=payload["headers"],
144
+ payload=payload,
145
+ headers=headers,
193
146
  endpoint=self.endpoint,
194
- is_cached=payload.get("is_cached", False),
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
- "provider": self.endpoint.config.provider,
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
- provider = data.pop("provider", None)
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
- endpoint_config_params["endpoint"] = endpoint_config_params.get(
380
- "endpoint", "chat"
303
+ e1 = match_endpoint(
304
+ provider=endpoint.config.provider,
305
+ endpoint=endpoint.config.endpoint,
381
306
  )
382
- match_params = {}
383
307
 
384
- for i in ("provider", "base_url", "endpoint", "endpoint_params"):
385
- if endpoint_config_params.get(i):
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
- provider=provider,
391
- base_url=base_url,
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)
@@ -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.endpoint, ChatCompletionEndPoint):
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 .base import APICalling
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(self, required_tokens: int = None) -> bool:
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: