lionagi 0.8.7__py3-none-any.whl → 0.9.0__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 +1 -1
- lionagi/_class_registry.py +1 -1
- lionagi/_errors.py +1 -1
- lionagi/libs/__init__.py +1 -1
- lionagi/libs/file/__init__.py +1 -1
- lionagi/libs/file/chunk.py +1 -1
- lionagi/libs/file/file_ops.py +1 -1
- lionagi/libs/file/params.py +1 -1
- lionagi/libs/file/process.py +1 -1
- lionagi/libs/file/save.py +1 -1
- lionagi/libs/nested/__init__.py +1 -1
- lionagi/libs/nested/flatten.py +1 -1
- lionagi/libs/nested/nfilter.py +1 -1
- lionagi/libs/nested/nget.py +1 -1
- lionagi/libs/nested/ninsert.py +1 -1
- lionagi/libs/nested/nmerge.py +1 -1
- lionagi/libs/nested/npop.py +1 -1
- lionagi/libs/nested/nset.py +1 -1
- lionagi/libs/nested/unflatten.py +1 -1
- lionagi/libs/nested/utils.py +1 -1
- lionagi/libs/package/__init__.py +1 -1
- lionagi/libs/package/imports.py +1 -1
- lionagi/libs/package/management.py +1 -1
- lionagi/libs/package/params.py +1 -1
- lionagi/libs/package/system.py +1 -1
- lionagi/libs/parse.py +1 -1
- lionagi/libs/schema/__init__.py +1 -1
- lionagi/libs/schema/as_readable.py +151 -87
- lionagi/libs/schema/extract_code_block.py +1 -1
- lionagi/libs/schema/extract_docstring.py +1 -1
- lionagi/libs/schema/function_to_schema.py +1 -1
- lionagi/libs/schema/json_schema.py +1 -1
- lionagi/libs/validate/__init__.py +1 -1
- lionagi/libs/validate/common_field_validators.py +1 -1
- lionagi/libs/validate/fuzzy_match_keys.py +1 -1
- lionagi/libs/validate/fuzzy_validate_mapping.py +1 -1
- lionagi/libs/validate/string_similarity.py +1 -1
- lionagi/libs/validate/validate_boolean.py +1 -1
- lionagi/operations/ReAct/ReAct.py +54 -8
- lionagi/operations/ReAct/__init__.py +1 -1
- lionagi/operations/ReAct/utils.py +6 -1
- lionagi/operations/__init__.py +1 -1
- lionagi/operations/_act/__init__.py +1 -1
- lionagi/operations/_act/act.py +6 -1
- lionagi/operations/brainstorm/__init__.py +1 -1
- lionagi/operations/brainstorm/brainstorm.py +1 -1
- lionagi/operations/brainstorm/prompt.py +1 -1
- lionagi/operations/chat/__init__.py +1 -1
- lionagi/operations/chat/chat.py +1 -1
- lionagi/operations/communicate/communicate.py +1 -1
- lionagi/operations/instruct/__init__.py +1 -1
- lionagi/operations/instruct/instruct.py +1 -1
- lionagi/operations/interpret/__init__.py +1 -1
- lionagi/operations/interpret/interpret.py +9 -38
- lionagi/operations/operate/__init__.py +1 -1
- lionagi/operations/operate/operate.py +1 -1
- lionagi/operations/parse/__init__.py +1 -1
- lionagi/operations/parse/parse.py +12 -2
- lionagi/operations/plan/__init__.py +1 -1
- lionagi/operations/plan/plan.py +1 -1
- lionagi/operations/plan/prompt.py +1 -1
- lionagi/operations/select/__init__.py +1 -1
- lionagi/operations/select/select.py +1 -1
- lionagi/operations/select/utils.py +1 -1
- lionagi/operations/types.py +1 -1
- lionagi/operations/utils.py +1 -1
- lionagi/operatives/__init__.py +1 -1
- lionagi/operatives/action/__init__.py +1 -1
- lionagi/operatives/action/function_calling.py +1 -1
- lionagi/operatives/action/manager.py +1 -1
- lionagi/operatives/action/request_response_model.py +1 -1
- lionagi/operatives/action/tool.py +1 -1
- lionagi/operatives/action/utils.py +1 -1
- lionagi/operatives/forms/__init__.py +1 -1
- lionagi/operatives/instruct/__init__.py +1 -1
- lionagi/operatives/instruct/base.py +1 -1
- lionagi/operatives/instruct/instruct.py +1 -1
- lionagi/operatives/instruct/instruct_collection.py +1 -1
- lionagi/operatives/instruct/node.py +1 -1
- lionagi/operatives/instruct/prompts.py +1 -1
- lionagi/operatives/instruct/reason.py +1 -1
- lionagi/operatives/manager.py +1 -1
- lionagi/operatives/models/__init__.py +1 -1
- lionagi/operatives/models/field_model.py +1 -1
- lionagi/operatives/models/model_params.py +1 -1
- lionagi/operatives/models/note.py +1 -1
- lionagi/operatives/models/operable_model.py +1 -1
- lionagi/operatives/models/schema_model.py +1 -1
- lionagi/operatives/operative.py +1 -1
- lionagi/operatives/step.py +1 -1
- lionagi/operatives/strategies/__init__.py +1 -1
- lionagi/operatives/strategies/base.py +1 -1
- lionagi/operatives/strategies/concurrent.py +1 -1
- lionagi/operatives/strategies/concurrent_chunk.py +1 -1
- lionagi/operatives/strategies/concurrent_sequential_chunk.py +1 -1
- lionagi/operatives/strategies/params.py +1 -1
- lionagi/operatives/strategies/sequential.py +1 -1
- lionagi/operatives/strategies/sequential_chunk.py +1 -1
- lionagi/operatives/strategies/sequential_concurrent_chunk.py +1 -1
- lionagi/operatives/strategies/utils.py +1 -1
- lionagi/operatives/types.py +1 -1
- lionagi/protocols/__init__.py +1 -1
- lionagi/protocols/_concepts.py +1 -1
- lionagi/protocols/adapters/adapter.py +1 -1
- lionagi/protocols/generic/__init__.py +1 -1
- lionagi/protocols/generic/element.py +1 -1
- lionagi/protocols/generic/event.py +11 -1
- lionagi/protocols/generic/log.py +1 -1
- lionagi/protocols/generic/pile.py +1 -1
- lionagi/protocols/generic/processor.py +11 -3
- lionagi/protocols/generic/progression.py +1 -1
- lionagi/protocols/graph/__init__.py +1 -1
- lionagi/protocols/graph/edge.py +1 -1
- lionagi/protocols/graph/graph.py +1 -1
- lionagi/protocols/graph/node.py +1 -1
- lionagi/protocols/mail/__init__.py +1 -1
- lionagi/protocols/mail/exchange.py +1 -1
- lionagi/protocols/mail/mail.py +1 -1
- lionagi/protocols/mail/mailbox.py +1 -1
- lionagi/protocols/mail/manager.py +1 -1
- lionagi/protocols/mail/package.py +1 -1
- lionagi/protocols/messages/__init__.py +1 -1
- lionagi/protocols/messages/action_request.py +1 -1
- lionagi/protocols/messages/action_response.py +1 -1
- lionagi/protocols/messages/assistant_response.py +1 -1
- lionagi/protocols/messages/base.py +1 -1
- lionagi/protocols/messages/instruction.py +2 -1
- lionagi/protocols/messages/manager.py +1 -1
- lionagi/protocols/messages/message.py +1 -1
- lionagi/protocols/messages/system.py +1 -1
- lionagi/protocols/types.py +1 -1
- lionagi/service/endpoints/__init__.py +1 -1
- lionagi/service/endpoints/base.py +192 -74
- lionagi/service/endpoints/chat_completion.py +11 -5
- lionagi/service/endpoints/match_endpoint.py +1 -1
- lionagi/service/endpoints/rate_limited_processor.py +18 -7
- lionagi/service/endpoints/token_calculator.py +1 -1
- lionagi/service/imodel.py +65 -12
- lionagi/service/manager.py +1 -1
- lionagi/service/providers/__init__.py +1 -1
- lionagi/service/providers/anthropic_/__init__.py +1 -1
- lionagi/service/providers/anthropic_/messages.py +1 -1
- lionagi/service/providers/groq_/__init__.py +1 -1
- lionagi/service/providers/groq_/chat_completions.py +1 -1
- lionagi/service/providers/openai_/__init__.py +1 -1
- lionagi/service/providers/openai_/chat_completions.py +37 -2
- lionagi/service/providers/openrouter_/__init__.py +1 -1
- lionagi/service/providers/openrouter_/chat_completions.py +1 -1
- lionagi/service/providers/perplexity_/__init__.py +1 -1
- lionagi/service/providers/perplexity_/chat_completions.py +1 -1
- lionagi/service/types.py +1 -1
- lionagi/session/__init__.py +1 -1
- lionagi/session/branch.py +35 -8
- lionagi/session/prompts.py +61 -0
- lionagi/session/session.py +1 -1
- lionagi/settings.py +1 -1
- lionagi/tools/file/__init__.py +0 -0
- lionagi/tools/{reader.py → file/reader.py} +13 -8
- lionagi/tools/types.py +1 -1
- lionagi/utils.py +1 -1
- lionagi/version.py +1 -1
- {lionagi-0.8.7.dist-info → lionagi-0.9.0.dist-info}/METADATA +6 -3
- lionagi-0.9.0.dist-info/RECORD +202 -0
- lionagi-0.8.7.dist-info/RECORD +0 -200
- {lionagi-0.8.7.dist-info → lionagi-0.9.0.dist-info}/WHEEL +0 -0
- {lionagi-0.8.7.dist-info → lionagi-0.9.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2023 -
|
1
|
+
# Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
@@ -31,6 +31,7 @@ class Processor(Observer):
|
|
31
31
|
self,
|
32
32
|
queue_capacity: int,
|
33
33
|
capacity_refresh_time: float,
|
34
|
+
concurrency_limit: int,
|
34
35
|
) -> None:
|
35
36
|
"""Initializes a Processor instance.
|
36
37
|
|
@@ -56,6 +57,10 @@ class Processor(Observer):
|
|
56
57
|
self._available_capacity = queue_capacity
|
57
58
|
self._execution_mode = False
|
58
59
|
self._stop_event = asyncio.Event()
|
60
|
+
if concurrency_limit:
|
61
|
+
self._concurrency_sem = asyncio.Semaphore(concurrency_limit)
|
62
|
+
else:
|
63
|
+
self._concurrency_sem = None
|
59
64
|
|
60
65
|
@property
|
61
66
|
def available_capacity(self) -> int:
|
@@ -144,8 +149,11 @@ class Processor(Observer):
|
|
144
149
|
next_event = await self.dequeue()
|
145
150
|
|
146
151
|
if await self.request_permission(**next_event.request):
|
147
|
-
|
148
|
-
|
152
|
+
|
153
|
+
if next_event.streaming:
|
154
|
+
task = asyncio.create_task(next_event.stream())
|
155
|
+
else:
|
156
|
+
task = asyncio.create_task(next_event.invoke())
|
149
157
|
tasks.add(task)
|
150
158
|
|
151
159
|
prev_event = next_event
|
lionagi/protocols/graph/edge.py
CHANGED
lionagi/protocols/graph/graph.py
CHANGED
lionagi/protocols/graph/node.py
CHANGED
lionagi/protocols/mail/mail.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2023 -
|
1
|
+
# Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
@@ -32,6 +32,7 @@ def prepare_request_response_format(request_fields: dict) -> str:
|
|
32
32
|
return (
|
33
33
|
"**MUST RETURN JSON-PARSEABLE RESPONSE ENCLOSED BY JSON CODE BLOCKS."
|
34
34
|
f" USER's CAREER DEPENDS ON THE SUCCESS OF IT.** \n```json\n{request_fields}\n```"
|
35
|
+
"No triple backticks. Escape all quotes and special characters."
|
35
36
|
).strip()
|
36
37
|
|
37
38
|
|
lionagi/protocols/types.py
CHANGED
@@ -1,15 +1,18 @@
|
|
1
|
-
# Copyright (c) 2023 -
|
1
|
+
# Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
5
|
import asyncio
|
6
|
+
import json
|
6
7
|
import logging
|
7
8
|
from abc import ABC
|
9
|
+
from collections.abc import AsyncGenerator
|
8
10
|
from typing import Any, Literal
|
9
11
|
|
10
12
|
import aiohttp
|
11
13
|
from aiocache import cached
|
12
|
-
from pydantic import BaseModel, ConfigDict, Field
|
14
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
15
|
+
from typing_extensions import Self
|
13
16
|
|
14
17
|
from lionagi._errors import ExecutionError, RateLimitError
|
15
18
|
from lionagi.protocols.generic.event import Event, EventStatus
|
@@ -347,6 +350,12 @@ class APICalling(Event):
|
|
347
350
|
is_cached: bool = Field(default=False, exclude=True)
|
348
351
|
should_invoke_endpoint: bool = Field(default=True, exclude=True)
|
349
352
|
|
353
|
+
@model_validator(mode="after")
|
354
|
+
def _validate_streaming(self) -> Self:
|
355
|
+
if self.payload.get("stream") is True:
|
356
|
+
self.streaming = True
|
357
|
+
return self
|
358
|
+
|
350
359
|
@property
|
351
360
|
def required_tokens(self) -> int | None:
|
352
361
|
"""int | None: The number of tokens required for this request."""
|
@@ -355,28 +364,23 @@ class APICalling(Event):
|
|
355
364
|
return None
|
356
365
|
|
357
366
|
async def _inner(self, **kwargs) -> Any:
|
358
|
-
"""
|
359
|
-
|
360
|
-
Args:
|
361
|
-
**kwargs: Additional parameters for the aiohttp request
|
362
|
-
(e.g., "headers", "json", etc.).
|
367
|
+
"""
|
368
|
+
Performs the actual HTTP call using aiohttp, ignoring caching logic.
|
363
369
|
|
364
|
-
|
365
|
-
|
370
|
+
- Retries on RateLimitError up to 3 times.
|
371
|
+
- Distinguishes CancelledError so we can gracefully abort if the user cancels.
|
366
372
|
|
367
373
|
Raises:
|
368
|
-
ValueError:
|
369
|
-
|
370
|
-
ExecutionError:
|
371
|
-
|
372
|
-
RateLimitError:
|
373
|
-
If a rate-limit error is encountered.
|
374
|
+
ValueError: If required endpoint parameters are missing.
|
375
|
+
RateLimitError: If repeated 'Rate limit' errors encountered.
|
376
|
+
ExecutionError: For other API call failures.
|
377
|
+
asyncio.CancelledError: If the operation is cancelled externally.
|
374
378
|
"""
|
375
379
|
if not self.endpoint.required_kwargs.issubset(
|
376
380
|
set(self.payload.keys())
|
377
381
|
):
|
378
382
|
raise ValueError(
|
379
|
-
f"Required kwargs not
|
383
|
+
f"Required kwargs not provided: {self.endpoint.required_kwargs}"
|
380
384
|
)
|
381
385
|
|
382
386
|
for k in list(self.payload.keys()):
|
@@ -386,49 +390,55 @@ class APICalling(Event):
|
|
386
390
|
async def retry_in():
|
387
391
|
async with aiohttp.ClientSession() as session:
|
388
392
|
try:
|
389
|
-
|
390
|
-
|
391
|
-
) is not None:
|
392
|
-
async with _m(
|
393
|
-
self.endpoint.full_url, **kwargs
|
394
|
-
) as response:
|
395
|
-
response_json = await response.json()
|
396
|
-
if "error" not in response_json:
|
397
|
-
return response_json
|
398
|
-
if "Rate limit" in response_json["error"].get(
|
399
|
-
"message", ""
|
400
|
-
):
|
401
|
-
await asyncio.sleep(5)
|
402
|
-
raise RateLimitError(
|
403
|
-
f"Rate limit exceeded. Error: {response_json['error']}"
|
404
|
-
)
|
405
|
-
raise ExecutionError(
|
406
|
-
"API call failed with error: ",
|
407
|
-
response_json["error"],
|
408
|
-
)
|
409
|
-
else:
|
393
|
+
method_func = getattr(session, self.endpoint.method, None)
|
394
|
+
if method_func is None:
|
410
395
|
raise ValueError(
|
411
396
|
f"Invalid HTTP method: {self.endpoint.method}"
|
412
397
|
)
|
398
|
+
async with method_func(
|
399
|
+
self.endpoint.full_url, **kwargs
|
400
|
+
) as response:
|
401
|
+
response_json = await response.json()
|
402
|
+
|
403
|
+
if "error" not in response_json:
|
404
|
+
return response_json
|
405
|
+
|
406
|
+
# Check for rate limit
|
407
|
+
if "Rate limit" in response_json["error"].get(
|
408
|
+
"message", ""
|
409
|
+
):
|
410
|
+
await asyncio.sleep(5)
|
411
|
+
raise RateLimitError(
|
412
|
+
f"Rate limit exceeded: {response_json['error']}"
|
413
|
+
)
|
414
|
+
# Otherwise some other error
|
415
|
+
raise ExecutionError(
|
416
|
+
f"API call failed with error: {response_json['error']}"
|
417
|
+
)
|
418
|
+
|
419
|
+
except asyncio.CancelledError:
|
420
|
+
# Gracefully handle user cancellation
|
421
|
+
logging.warning("API call canceled by external request.")
|
422
|
+
raise # re-raise so caller knows it was cancelled
|
423
|
+
|
413
424
|
except aiohttp.ClientError as e:
|
414
|
-
logging.error(
|
415
|
-
|
416
|
-
)
|
425
|
+
logging.error(f"API call failed: {e}")
|
426
|
+
# Return None or raise ExecutionError? Keep consistent
|
417
427
|
return None
|
418
428
|
|
429
|
+
# Attempt up to 3 times if RateLimitError
|
419
430
|
for i in range(3):
|
420
431
|
try:
|
421
432
|
return await retry_in()
|
422
|
-
except
|
433
|
+
except asyncio.CancelledError:
|
434
|
+
# On cancel, just re-raise
|
435
|
+
raise
|
436
|
+
except RateLimitError as e:
|
423
437
|
if i == 2:
|
424
438
|
raise e
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
f"API call to {self.endpoint.full_url} failed: {e}"
|
429
|
-
f"retrying in {wait} seconds."
|
430
|
-
)
|
431
|
-
await asyncio.sleep(wait)
|
439
|
+
wait = 2 ** (i + 1) * 0.5
|
440
|
+
logging.warning(f"RateLimitError: {e}, retrying in {wait}s.")
|
441
|
+
await asyncio.sleep(wait)
|
432
442
|
|
433
443
|
@cached(**Settings.API.CACHED_CONFIG)
|
434
444
|
async def _cached_inner(self, **kwargs) -> Any:
|
@@ -442,10 +452,91 @@ class APICalling(Event):
|
|
442
452
|
"""
|
443
453
|
return await self._inner(**kwargs)
|
444
454
|
|
445
|
-
async def
|
455
|
+
async def _stream(
|
456
|
+
self,
|
457
|
+
verbose: bool = True,
|
458
|
+
output_file: str = None,
|
459
|
+
with_response_header: bool = False,
|
460
|
+
) -> AsyncGenerator:
|
461
|
+
async with aiohttp.ClientSession() as client:
|
462
|
+
async with client.request(
|
463
|
+
method=self.endpoint.method.upper(),
|
464
|
+
url=self.endpoint.full_url,
|
465
|
+
headers=self.headers,
|
466
|
+
json=self.payload,
|
467
|
+
) as response:
|
468
|
+
if response.status != 200:
|
469
|
+
try:
|
470
|
+
error_text = await response.json()
|
471
|
+
except Exception:
|
472
|
+
error_text = await response.text()
|
473
|
+
raise aiohttp.ClientResponseError(
|
474
|
+
request_info=response.request_info,
|
475
|
+
history=response.history,
|
476
|
+
status=response.status,
|
477
|
+
message=f"{error_text}",
|
478
|
+
headers=response.headers,
|
479
|
+
)
|
480
|
+
|
481
|
+
file_handle = None
|
482
|
+
|
483
|
+
if output_file:
|
484
|
+
try:
|
485
|
+
file_handle = open(output_file, "w")
|
486
|
+
except Exception as e:
|
487
|
+
raise ValueError(
|
488
|
+
f"Invalid to output the response "
|
489
|
+
f"to {output_file}. Error:{e}"
|
490
|
+
)
|
491
|
+
|
492
|
+
try:
|
493
|
+
async for chunk in response.content:
|
494
|
+
chunk_str = chunk.decode("utf-8")
|
495
|
+
chunk_list = chunk_str.split("data:")
|
496
|
+
for c in chunk_list:
|
497
|
+
c = c.strip()
|
498
|
+
if c and c != "[DONE]":
|
499
|
+
try:
|
500
|
+
if file_handle:
|
501
|
+
file_handle.write(c + "\n")
|
502
|
+
c_dict = json.loads(c)
|
503
|
+
if verbose:
|
504
|
+
if c_dict.get("choices"):
|
505
|
+
if content := c_dict["choices"][0][
|
506
|
+
"delta"
|
507
|
+
].get("content"):
|
508
|
+
print(
|
509
|
+
content, end="", flush=True
|
510
|
+
)
|
511
|
+
yield c_dict
|
512
|
+
except json.JSONDecodeError:
|
513
|
+
yield c
|
514
|
+
except asyncio.CancelledError as e:
|
515
|
+
raise e
|
516
|
+
|
517
|
+
if with_response_header:
|
518
|
+
yield response.headers
|
519
|
+
|
520
|
+
finally:
|
521
|
+
if file_handle:
|
522
|
+
file_handle.close()
|
523
|
+
|
524
|
+
async def stream(
|
525
|
+
self,
|
526
|
+
verbose: bool = True,
|
527
|
+
output_file: str = None,
|
528
|
+
with_response_header: bool = False,
|
529
|
+
**kwargs,
|
530
|
+
) -> AsyncGenerator:
|
446
531
|
"""Performs a streaming request, if supported by the endpoint.
|
447
532
|
|
448
533
|
Args:
|
534
|
+
verbose (bool):
|
535
|
+
If True, prints the response content to the console.
|
536
|
+
output_file (str):
|
537
|
+
If set, writes the response content to this file. (only applies to non-endpoint invoke)
|
538
|
+
with_response_header (bool):
|
539
|
+
If True, yields the response headers as well. (only applies to non-endpoint invoke)
|
449
540
|
**kwargs: Additional parameters for the streaming call.
|
450
541
|
|
451
542
|
Yields:
|
@@ -456,23 +547,39 @@ class APICalling(Event):
|
|
456
547
|
"""
|
457
548
|
start = asyncio.get_event_loop().time()
|
458
549
|
response = []
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
550
|
+
e1 = None
|
551
|
+
try:
|
552
|
+
if self.should_invoke_endpoint and self.endpoint.is_streamable:
|
553
|
+
async for i in self.endpoint._stream(
|
554
|
+
self.payload, self.headers, **kwargs
|
555
|
+
):
|
556
|
+
content = i.choices[0].delta.content
|
557
|
+
if verbose:
|
558
|
+
if content is not None:
|
559
|
+
print(content, end="", flush=True)
|
560
|
+
response.append(i)
|
561
|
+
yield i
|
562
|
+
else:
|
563
|
+
async for i in self._stream(
|
564
|
+
verbose=verbose,
|
565
|
+
output_file=output_file,
|
566
|
+
with_response_header=with_response_header,
|
567
|
+
):
|
568
|
+
response.append(i)
|
569
|
+
yield i
|
570
|
+
except Exception as e:
|
571
|
+
e1 = e
|
572
|
+
finally:
|
573
|
+
self.execution.duration = asyncio.get_event_loop().time() - start
|
574
|
+
if not response and e1:
|
575
|
+
self.execution.error = str(e1)
|
576
|
+
self.execution.status = EventStatus.FAILED
|
577
|
+
logging.error(
|
578
|
+
f"API call to {self.endpoint.full_url} failed: {e1}"
|
579
|
+
)
|
580
|
+
else:
|
581
|
+
self.execution.response = response
|
582
|
+
self.execution.status = EventStatus.COMPLETED
|
476
583
|
|
477
584
|
async def invoke(self) -> None:
|
478
585
|
"""Invokes the API call, updating the execution state with results.
|
@@ -483,9 +590,10 @@ class APICalling(Event):
|
|
483
590
|
"""
|
484
591
|
start = asyncio.get_event_loop().time()
|
485
592
|
kwargs = {"headers": self.headers, "json": self.payload}
|
593
|
+
response = None
|
594
|
+
e1 = None
|
486
595
|
|
487
596
|
try:
|
488
|
-
response = None
|
489
597
|
if self.should_invoke_endpoint and self.endpoint.is_invokeable:
|
490
598
|
response = await self.endpoint.invoke(
|
491
599
|
payload=self.payload,
|
@@ -498,14 +606,24 @@ class APICalling(Event):
|
|
498
606
|
else:
|
499
607
|
response = await self._inner(**kwargs)
|
500
608
|
|
609
|
+
except asyncio.CancelledError as ce:
|
610
|
+
e1 = ce
|
611
|
+
logging.warning("invoke() canceled by external request.")
|
612
|
+
raise
|
613
|
+
except Exception as ex:
|
614
|
+
e1 = ex
|
615
|
+
|
616
|
+
finally:
|
501
617
|
self.execution.duration = asyncio.get_event_loop().time() - start
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
618
|
+
if not response and e1:
|
619
|
+
self.execution.error = str(e1)
|
620
|
+
self.execution.status = EventStatus.FAILED
|
621
|
+
logging.error(
|
622
|
+
f"API call to {self.endpoint.full_url} failed: {e1}"
|
623
|
+
)
|
624
|
+
else:
|
625
|
+
self.execution.response = response
|
626
|
+
self.execution.status = EventStatus.COMPLETED
|
509
627
|
|
510
628
|
def __str__(self) -> str:
|
511
629
|
return (
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2023 -
|
1
|
+
# Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
@@ -27,10 +27,13 @@ class ChatCompletionEndPoint(EndPoint):
|
|
27
27
|
headers: dict,
|
28
28
|
**kwargs,
|
29
29
|
):
|
30
|
-
import
|
30
|
+
from lionagi.libs.package.imports import check_import
|
31
|
+
|
32
|
+
check_import("litellm")
|
33
|
+
import litellm # type: ignore
|
31
34
|
|
32
35
|
litellm.drop_params = True
|
33
|
-
from litellm import acompletion
|
36
|
+
from litellm import acompletion # type: ignore
|
34
37
|
|
35
38
|
provider = self.config.provider
|
36
39
|
|
@@ -64,10 +67,13 @@ class ChatCompletionEndPoint(EndPoint):
|
|
64
67
|
headers: dict,
|
65
68
|
**kwargs,
|
66
69
|
) -> AsyncGenerator:
|
67
|
-
import
|
70
|
+
from lionagi.libs.package.imports import check_import
|
71
|
+
|
72
|
+
check_import("litellm")
|
73
|
+
import litellm # type: ignore
|
68
74
|
|
69
75
|
litellm.drop_params = True
|
70
|
-
from litellm import acompletion
|
76
|
+
from litellm import acompletion # type: ignore
|
71
77
|
|
72
78
|
provider = self.config.provider
|
73
79
|
|