lionagi 0.1.2__py3-none-any.whl → 0.2.1__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 +60 -5
- lionagi/core/__init__.py +0 -25
- lionagi/core/_setting/_setting.py +59 -0
- lionagi/core/action/__init__.py +14 -0
- lionagi/core/action/function_calling.py +136 -0
- lionagi/core/action/manual.py +1 -0
- lionagi/core/action/node.py +109 -0
- lionagi/core/action/tool.py +114 -0
- lionagi/core/action/tool_manager.py +356 -0
- lionagi/core/agent/base_agent.py +27 -13
- lionagi/core/agent/eval/evaluator.py +1 -0
- lionagi/core/agent/eval/vote.py +40 -0
- lionagi/core/agent/learn/learner.py +59 -0
- lionagi/core/agent/plan/unit_template.py +1 -0
- lionagi/core/collections/__init__.py +17 -0
- lionagi/core/{generic/data_logger.py → collections/_logger.py} +69 -55
- lionagi/core/collections/abc/__init__.py +53 -0
- lionagi/core/collections/abc/component.py +615 -0
- lionagi/core/collections/abc/concepts.py +297 -0
- lionagi/core/collections/abc/exceptions.py +150 -0
- lionagi/core/collections/abc/util.py +45 -0
- lionagi/core/collections/exchange.py +161 -0
- lionagi/core/collections/flow.py +426 -0
- lionagi/core/collections/model.py +419 -0
- lionagi/core/collections/pile.py +913 -0
- lionagi/core/collections/progression.py +236 -0
- lionagi/core/collections/util.py +64 -0
- lionagi/core/director/direct.py +314 -0
- lionagi/core/director/director.py +2 -0
- lionagi/core/{execute/branch_executor.py → engine/branch_engine.py} +134 -97
- lionagi/core/{execute/instruction_map_executor.py → engine/instruction_map_engine.py} +80 -55
- lionagi/{experimental/directive/evaluator → core/engine}/script_engine.py +17 -1
- lionagi/core/executor/base_executor.py +90 -0
- lionagi/core/{execute/structure_executor.py → executor/graph_executor.py} +62 -66
- lionagi/core/{execute → executor}/neo4j_executor.py +70 -67
- lionagi/core/generic/__init__.py +3 -33
- lionagi/core/generic/edge.py +29 -79
- lionagi/core/generic/edge_condition.py +16 -0
- lionagi/core/generic/graph.py +236 -0
- lionagi/core/generic/hyperedge.py +1 -0
- lionagi/core/generic/node.py +156 -221
- lionagi/core/generic/tree.py +48 -0
- lionagi/core/generic/tree_node.py +79 -0
- lionagi/core/mail/__init__.py +12 -0
- lionagi/core/mail/mail.py +25 -0
- lionagi/core/mail/mail_manager.py +139 -58
- lionagi/core/mail/package.py +45 -0
- lionagi/core/mail/start_mail.py +36 -0
- lionagi/core/message/__init__.py +19 -0
- lionagi/core/message/action_request.py +133 -0
- lionagi/core/message/action_response.py +135 -0
- lionagi/core/message/assistant_response.py +95 -0
- lionagi/core/message/instruction.py +234 -0
- lionagi/core/message/message.py +101 -0
- lionagi/core/message/system.py +86 -0
- lionagi/core/message/util.py +283 -0
- lionagi/core/report/__init__.py +4 -0
- lionagi/core/report/base.py +217 -0
- lionagi/core/report/form.py +231 -0
- lionagi/core/report/report.py +166 -0
- lionagi/core/report/util.py +28 -0
- lionagi/core/rule/_default.py +16 -0
- lionagi/core/rule/action.py +99 -0
- lionagi/core/rule/base.py +238 -0
- lionagi/core/rule/boolean.py +56 -0
- lionagi/core/rule/choice.py +47 -0
- lionagi/core/rule/mapping.py +96 -0
- lionagi/core/rule/number.py +71 -0
- lionagi/core/rule/rulebook.py +109 -0
- lionagi/core/rule/string.py +52 -0
- lionagi/core/rule/util.py +35 -0
- lionagi/core/session/branch.py +431 -0
- lionagi/core/session/directive_mixin.py +287 -0
- lionagi/core/session/session.py +229 -903
- lionagi/core/structure/__init__.py +1 -0
- lionagi/core/structure/chain.py +1 -0
- lionagi/core/structure/forest.py +1 -0
- lionagi/core/structure/graph.py +1 -0
- lionagi/core/structure/tree.py +1 -0
- lionagi/core/unit/__init__.py +5 -0
- lionagi/core/unit/parallel_unit.py +245 -0
- lionagi/core/unit/template/action.py +81 -0
- lionagi/core/unit/template/base.py +51 -0
- lionagi/core/unit/template/plan.py +84 -0
- lionagi/core/unit/template/predict.py +109 -0
- lionagi/core/unit/template/score.py +124 -0
- lionagi/core/unit/template/select.py +104 -0
- lionagi/core/unit/unit.py +362 -0
- lionagi/core/unit/unit_form.py +305 -0
- lionagi/core/unit/unit_mixin.py +1168 -0
- lionagi/core/unit/util.py +71 -0
- lionagi/core/validator/validator.py +364 -0
- lionagi/core/work/work.py +76 -0
- lionagi/core/work/work_function.py +101 -0
- lionagi/core/work/work_queue.py +103 -0
- lionagi/core/work/worker.py +258 -0
- lionagi/core/work/worklog.py +120 -0
- lionagi/experimental/compressor/base.py +46 -0
- lionagi/experimental/compressor/llm_compressor.py +247 -0
- lionagi/experimental/compressor/llm_summarizer.py +61 -0
- lionagi/experimental/compressor/util.py +70 -0
- lionagi/experimental/directive/__init__.py +19 -0
- lionagi/experimental/directive/parser/base_parser.py +69 -2
- lionagi/experimental/directive/{template_ → template}/base_template.py +17 -1
- lionagi/{libs/ln_tokenizer.py → experimental/directive/tokenizer.py} +16 -0
- lionagi/experimental/{directive/evaluator → evaluator}/ast_evaluator.py +16 -0
- lionagi/experimental/{directive/evaluator → evaluator}/base_evaluator.py +16 -0
- lionagi/experimental/knowledge/base.py +10 -0
- lionagi/experimental/memory/__init__.py +0 -0
- lionagi/experimental/strategies/__init__.py +0 -0
- lionagi/experimental/strategies/base.py +1 -0
- lionagi/integrations/bridge/langchain_/documents.py +4 -0
- lionagi/integrations/bridge/llamaindex_/index.py +30 -0
- lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +6 -0
- lionagi/integrations/chunker/chunk.py +161 -24
- lionagi/integrations/config/oai_configs.py +34 -3
- lionagi/integrations/config/openrouter_configs.py +14 -2
- lionagi/integrations/loader/load.py +122 -21
- lionagi/integrations/loader/load_util.py +6 -77
- lionagi/integrations/provider/_mapping.py +46 -0
- lionagi/integrations/provider/litellm.py +2 -1
- lionagi/integrations/provider/mlx_service.py +16 -9
- lionagi/integrations/provider/oai.py +91 -4
- lionagi/integrations/provider/ollama.py +6 -5
- lionagi/integrations/provider/openrouter.py +115 -8
- lionagi/integrations/provider/services.py +2 -2
- lionagi/integrations/provider/transformers.py +18 -22
- lionagi/integrations/storage/__init__.py +3 -3
- lionagi/integrations/storage/neo4j.py +52 -60
- lionagi/integrations/storage/storage_util.py +44 -46
- lionagi/integrations/storage/structure_excel.py +43 -26
- lionagi/integrations/storage/to_excel.py +11 -4
- lionagi/libs/__init__.py +22 -1
- lionagi/libs/ln_api.py +75 -20
- lionagi/libs/ln_context.py +37 -0
- lionagi/libs/ln_convert.py +21 -9
- lionagi/libs/ln_func_call.py +69 -28
- lionagi/libs/ln_image.py +107 -0
- lionagi/libs/ln_nested.py +26 -11
- lionagi/libs/ln_parse.py +82 -23
- lionagi/libs/ln_queue.py +16 -0
- lionagi/libs/ln_tokenize.py +164 -0
- lionagi/libs/ln_validate.py +16 -0
- lionagi/libs/special_tokens.py +172 -0
- lionagi/libs/sys_util.py +95 -24
- lionagi/lions/coder/code_form.py +13 -0
- lionagi/lions/coder/coder.py +50 -3
- lionagi/lions/coder/util.py +30 -25
- lionagi/tests/libs/test_func_call.py +23 -21
- lionagi/tests/libs/test_nested.py +36 -21
- lionagi/tests/libs/test_parse.py +1 -1
- lionagi/tests/test_core/collections/__init__.py +0 -0
- lionagi/tests/test_core/collections/test_component.py +206 -0
- lionagi/tests/test_core/collections/test_exchange.py +138 -0
- lionagi/tests/test_core/collections/test_flow.py +145 -0
- lionagi/tests/test_core/collections/test_pile.py +171 -0
- lionagi/tests/test_core/collections/test_progression.py +129 -0
- lionagi/tests/test_core/generic/test_edge.py +67 -0
- lionagi/tests/test_core/generic/test_graph.py +96 -0
- lionagi/tests/test_core/generic/test_node.py +106 -0
- lionagi/tests/test_core/generic/test_tree_node.py +73 -0
- lionagi/tests/test_core/test_branch.py +115 -294
- lionagi/tests/test_core/test_form.py +46 -0
- lionagi/tests/test_core/test_report.py +105 -0
- lionagi/tests/test_core/test_validator.py +111 -0
- lionagi/version.py +1 -1
- lionagi-0.2.1.dist-info/LICENSE +202 -0
- lionagi-0.2.1.dist-info/METADATA +272 -0
- lionagi-0.2.1.dist-info/RECORD +240 -0
- lionagi/core/branch/base.py +0 -653
- lionagi/core/branch/branch.py +0 -474
- lionagi/core/branch/flow_mixin.py +0 -96
- lionagi/core/branch/util.py +0 -323
- lionagi/core/direct/__init__.py +0 -19
- lionagi/core/direct/cot.py +0 -123
- lionagi/core/direct/plan.py +0 -164
- lionagi/core/direct/predict.py +0 -166
- lionagi/core/direct/react.py +0 -171
- lionagi/core/direct/score.py +0 -279
- lionagi/core/direct/select.py +0 -170
- lionagi/core/direct/sentiment.py +0 -1
- lionagi/core/direct/utils.py +0 -110
- lionagi/core/direct/vote.py +0 -64
- lionagi/core/execute/base_executor.py +0 -47
- lionagi/core/flow/baseflow.py +0 -23
- lionagi/core/flow/monoflow/ReAct.py +0 -240
- lionagi/core/flow/monoflow/__init__.py +0 -9
- lionagi/core/flow/monoflow/chat.py +0 -95
- lionagi/core/flow/monoflow/chat_mixin.py +0 -253
- lionagi/core/flow/monoflow/followup.py +0 -215
- lionagi/core/flow/polyflow/__init__.py +0 -1
- lionagi/core/flow/polyflow/chat.py +0 -251
- lionagi/core/form/action_form.py +0 -26
- lionagi/core/form/field_validator.py +0 -287
- lionagi/core/form/form.py +0 -302
- lionagi/core/form/mixin.py +0 -214
- lionagi/core/form/scored_form.py +0 -13
- lionagi/core/generic/action.py +0 -26
- lionagi/core/generic/component.py +0 -532
- lionagi/core/generic/condition.py +0 -46
- lionagi/core/generic/mail.py +0 -90
- lionagi/core/generic/mailbox.py +0 -36
- lionagi/core/generic/relation.py +0 -70
- lionagi/core/generic/signal.py +0 -22
- lionagi/core/generic/structure.py +0 -362
- lionagi/core/generic/transfer.py +0 -20
- lionagi/core/generic/work.py +0 -40
- lionagi/core/graph/graph.py +0 -126
- lionagi/core/graph/tree.py +0 -190
- lionagi/core/mail/schema.py +0 -63
- lionagi/core/messages/schema.py +0 -325
- lionagi/core/tool/__init__.py +0 -5
- lionagi/core/tool/tool.py +0 -28
- lionagi/core/tool/tool_manager.py +0 -283
- lionagi/experimental/report/form.py +0 -64
- lionagi/experimental/report/report.py +0 -138
- lionagi/experimental/report/util.py +0 -47
- lionagi/experimental/tool/function_calling.py +0 -43
- lionagi/experimental/tool/manual.py +0 -66
- lionagi/experimental/tool/schema.py +0 -59
- lionagi/experimental/tool/tool_manager.py +0 -138
- lionagi/experimental/tool/util.py +0 -16
- lionagi/experimental/validator/rule.py +0 -139
- lionagi/experimental/validator/validator.py +0 -56
- lionagi/experimental/work/__init__.py +0 -10
- lionagi/experimental/work/async_queue.py +0 -54
- lionagi/experimental/work/schema.py +0 -73
- lionagi/experimental/work/work_function.py +0 -67
- lionagi/experimental/work/worker.py +0 -56
- lionagi/experimental/work2/form.py +0 -371
- lionagi/experimental/work2/report.py +0 -289
- lionagi/experimental/work2/schema.py +0 -30
- lionagi/experimental/work2/tests.py +0 -72
- lionagi/experimental/work2/work_function.py +0 -89
- lionagi/experimental/work2/worker.py +0 -12
- lionagi/integrations/bridge/llamaindex_/get_index.py +0 -294
- lionagi/tests/test_core/generic/test_component.py +0 -89
- lionagi/tests/test_core/test_base_branch.py +0 -426
- lionagi/tests/test_core/test_chat_flow.py +0 -63
- lionagi/tests/test_core/test_mail_manager.py +0 -75
- lionagi/tests/test_core/test_prompts.py +0 -51
- lionagi/tests/test_core/test_session.py +0 -254
- lionagi/tests/test_core/test_session_base_util.py +0 -313
- lionagi/tests/test_core/test_tool_manager.py +0 -95
- lionagi-0.1.2.dist-info/LICENSE +0 -9
- lionagi-0.1.2.dist-info/METADATA +0 -174
- lionagi-0.1.2.dist-info/RECORD +0 -206
- /lionagi/core/{branch → _setting}/__init__.py +0 -0
- /lionagi/core/{execute → agent/eval}/__init__.py +0 -0
- /lionagi/core/{flow → agent/learn}/__init__.py +0 -0
- /lionagi/core/{form → agent/plan}/__init__.py +0 -0
- /lionagi/core/{branch/executable_branch.py → agent/plan/plan.py} +0 -0
- /lionagi/core/{graph → director}/__init__.py +0 -0
- /lionagi/core/{messages → engine}/__init__.py +0 -0
- /lionagi/{experimental/directive/evaluator → core/engine}/sandbox_.py +0 -0
- /lionagi/{experimental/directive/evaluator → core/executor}/__init__.py +0 -0
- /lionagi/{experimental/directive/template_ → core/rule}/__init__.py +0 -0
- /lionagi/{experimental/report → core/unit/template}/__init__.py +0 -0
- /lionagi/{experimental/tool → core/validator}/__init__.py +0 -0
- /lionagi/{experimental/validator → core/work}/__init__.py +0 -0
- /lionagi/experimental/{work2 → compressor}/__init__.py +0 -0
- /lionagi/{core/flow/mono_chat_mixin.py → experimental/directive/template/__init__.py} +0 -0
- /lionagi/experimental/directive/{schema.py → template/schema.py} +0 -0
- /lionagi/experimental/{work2/util.py → evaluator/__init__.py} +0 -0
- /lionagi/experimental/{work2/work.py → knowledge/__init__.py} +0 -0
- /lionagi/{tests/libs/test_async.py → experimental/knowledge/graph.py} +0 -0
- {lionagi-0.1.2.dist-info → lionagi-0.2.1.dist-info}/WHEEL +0 -0
- {lionagi-0.1.2.dist-info → lionagi-0.2.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
"""
|
2
|
+
Copyright 2024 HaiyangLi
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
"""
|
16
|
+
|
17
|
+
import asyncio
|
18
|
+
from lionagi.core.work.work import WorkStatus
|
19
|
+
|
20
|
+
|
21
|
+
class WorkQueue:
|
22
|
+
"""
|
23
|
+
A class representing a queue for managing work.
|
24
|
+
|
25
|
+
Attributes:
|
26
|
+
capacity (int): The maximum number of tasks the queue can handle.
|
27
|
+
queue (asyncio.Queue): The queue holding the tasks.
|
28
|
+
_stop_event (asyncio.Event): Event to signal stopping `execute` of the queue.
|
29
|
+
available_capacity (int): The remaining number of tasks the queue can handle.
|
30
|
+
execution_mode (bool): If `execute` is running.
|
31
|
+
"""
|
32
|
+
|
33
|
+
def __init__(self, capacity=5):
|
34
|
+
if capacity < 0:
|
35
|
+
raise ValueError("initial capacity must be >= 0")
|
36
|
+
self.capacity = capacity
|
37
|
+
self.queue = asyncio.Queue()
|
38
|
+
self._stop_event = asyncio.Event()
|
39
|
+
self.available_capacity = capacity
|
40
|
+
self.execution_mode = False
|
41
|
+
|
42
|
+
async def enqueue(self, work) -> None:
|
43
|
+
"""Enqueue a work item."""
|
44
|
+
await self.queue.put(work)
|
45
|
+
|
46
|
+
async def dequeue(self):
|
47
|
+
"""Dequeue a work item."""
|
48
|
+
return await self.queue.get()
|
49
|
+
|
50
|
+
async def join(self) -> None:
|
51
|
+
"""Block until all items in the queue have been processed."""
|
52
|
+
await self.queue.join()
|
53
|
+
|
54
|
+
async def stop(self) -> None:
|
55
|
+
"""Signal the queue to stop processing."""
|
56
|
+
self._stop_event.set()
|
57
|
+
|
58
|
+
@property
|
59
|
+
def stopped(self) -> bool:
|
60
|
+
"""Return whether the queue has been stopped."""
|
61
|
+
return self._stop_event.is_set()
|
62
|
+
|
63
|
+
# async def process(self):
|
64
|
+
# async def _parse_work(work):
|
65
|
+
# async with self.semaphore:
|
66
|
+
# await work.perform()
|
67
|
+
#
|
68
|
+
# tasks = set()
|
69
|
+
# while self.queue.qsize() > 0:
|
70
|
+
# next = await self.dequeue()
|
71
|
+
# next.status = WorkStatus.IN_PROGRESS
|
72
|
+
# task = asyncio.create_task(_parse_work(next))
|
73
|
+
# tasks.add(task)
|
74
|
+
#
|
75
|
+
# await asyncio.wait(tasks)
|
76
|
+
|
77
|
+
async def process(self) -> None:
|
78
|
+
"""Process the work items in the queue."""
|
79
|
+
tasks = set()
|
80
|
+
while self.available_capacity > 0 and self.queue.qsize() > 0:
|
81
|
+
next = await self.dequeue()
|
82
|
+
next.status = WorkStatus.IN_PROGRESS
|
83
|
+
task = asyncio.create_task(next.perform())
|
84
|
+
tasks.add(task)
|
85
|
+
self.available_capacity -= 1
|
86
|
+
|
87
|
+
if tasks:
|
88
|
+
await asyncio.wait(tasks)
|
89
|
+
self.available_capacity = self.capacity
|
90
|
+
|
91
|
+
async def execute(self, refresh_time=1):
|
92
|
+
"""
|
93
|
+
Continuously executes the process method at a specified refresh interval.
|
94
|
+
|
95
|
+
Args:
|
96
|
+
refresh_time (int, optional): The time in seconds to wait between
|
97
|
+
successive calls to `process`. Defaults to 1.
|
98
|
+
"""
|
99
|
+
self.execution_mode = True
|
100
|
+
while not self.stopped:
|
101
|
+
await self.process()
|
102
|
+
await asyncio.sleep(refresh_time)
|
103
|
+
self.execution_mode = False
|
@@ -0,0 +1,258 @@
|
|
1
|
+
"""
|
2
|
+
Copyright 2024 HaiyangLi
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
"""
|
16
|
+
|
17
|
+
from abc import ABC
|
18
|
+
from functools import wraps
|
19
|
+
from typing import Callable
|
20
|
+
import asyncio
|
21
|
+
import inspect
|
22
|
+
from lionagi import logging as _logging
|
23
|
+
from lionagi.libs.ln_func_call import pcall
|
24
|
+
from lionagi.core.work.work_function import WorkFunction
|
25
|
+
from lionagi.core.work.work import Work
|
26
|
+
from lionagi.core.report.form import Form
|
27
|
+
from lionagi.core.collections.abc import get_lion_id
|
28
|
+
|
29
|
+
|
30
|
+
class Worker(ABC):
|
31
|
+
"""
|
32
|
+
This class represents a worker that handles multiple work functions.
|
33
|
+
|
34
|
+
Attributes:
|
35
|
+
name (str): The name of the worker.
|
36
|
+
work_functions (dict[str, WorkFunction]): Dictionary mapping assignments to WorkFunction objects.
|
37
|
+
forms (dict[str, Form]): Dictionary mapping form identifier to Form objects.
|
38
|
+
default_form (str|None): The default form to be used by the worker.
|
39
|
+
"""
|
40
|
+
|
41
|
+
name: str = "Worker"
|
42
|
+
work_functions: dict[str, WorkFunction] = {}
|
43
|
+
|
44
|
+
def __init__(self, forms=None, default_form=None) -> None:
|
45
|
+
# self.stopped = False
|
46
|
+
self.forms: dict[str, Form] = forms or {}
|
47
|
+
self.default_form = default_form
|
48
|
+
|
49
|
+
async def stop(self):
|
50
|
+
"""
|
51
|
+
Stops the worker and all associated work functions.
|
52
|
+
"""
|
53
|
+
# self.stopped = True
|
54
|
+
_logging.info(f"Stopping worker {self.name}")
|
55
|
+
non_stopped_ = []
|
56
|
+
|
57
|
+
for func in self.work_functions.values():
|
58
|
+
worklog = func.worklog
|
59
|
+
await worklog.stop()
|
60
|
+
if not worklog.stopped:
|
61
|
+
non_stopped_.append(func.name)
|
62
|
+
|
63
|
+
if len(non_stopped_) > 0:
|
64
|
+
_logging.error(f"Could not stop worklogs: {non_stopped_}")
|
65
|
+
_logging.info(f"Stopped worker {self.name}")
|
66
|
+
|
67
|
+
async def is_progressable(self):
|
68
|
+
"""
|
69
|
+
Checks if any work function is progressable and the worker is not stopped.
|
70
|
+
|
71
|
+
Returns:
|
72
|
+
bool: True if any work function is progressable and the worker is not stopped, else False.
|
73
|
+
"""
|
74
|
+
|
75
|
+
return (
|
76
|
+
any([await i.is_progressable() for i in self.work_functions.values()])
|
77
|
+
and not self.stopped
|
78
|
+
)
|
79
|
+
|
80
|
+
async def change_default_form(self, form_key):
|
81
|
+
"""
|
82
|
+
Changes the default form to the specified form key.
|
83
|
+
|
84
|
+
Args:
|
85
|
+
form_key (str): The key of the form to set as the default.
|
86
|
+
|
87
|
+
Raises:
|
88
|
+
ValueError: If the form key does not exist in the forms dictionary.
|
89
|
+
|
90
|
+
"""
|
91
|
+
if form_key not in self.forms.keys():
|
92
|
+
raise ValueError(f"Unable to change default form. Key {form_key} does not exist.")
|
93
|
+
self.default_form = self.forms[form_key]
|
94
|
+
|
95
|
+
# async def process(self, refresh_time=1):
|
96
|
+
# """
|
97
|
+
# Processes all work functions periodically.
|
98
|
+
#
|
99
|
+
# Args:
|
100
|
+
# refresh_time (int): Time interval between each process cycle.
|
101
|
+
# """
|
102
|
+
# while await self.is_progressable():
|
103
|
+
# await pcall([i.process(refresh_time) for i in self.work_functions.values()])
|
104
|
+
# await asyncio.sleep(refresh_time)
|
105
|
+
|
106
|
+
# TODO: Implement process method
|
107
|
+
|
108
|
+
# async def process(self, refresh_time=1):
|
109
|
+
# while not self.stopped:
|
110
|
+
# tasks = [
|
111
|
+
# asyncio.create_task(func.process(refresh_time=refresh_time))
|
112
|
+
# for func in self.work_functions.values()
|
113
|
+
# ]
|
114
|
+
# await asyncio.wait(tasks)
|
115
|
+
# await asyncio.sleep(refresh_time)
|
116
|
+
|
117
|
+
async def _wrapper(
|
118
|
+
self,
|
119
|
+
*args,
|
120
|
+
func=None,
|
121
|
+
assignment=None,
|
122
|
+
form_param_key=None,
|
123
|
+
capacity=None,
|
124
|
+
retry_kwargs=None,
|
125
|
+
guidance=None,
|
126
|
+
**kwargs,
|
127
|
+
):
|
128
|
+
"""
|
129
|
+
Internal wrapper to handle work function execution.
|
130
|
+
|
131
|
+
Args:
|
132
|
+
func (Callable): The function to be executed.
|
133
|
+
assignment (str): The assignment description.
|
134
|
+
form_param_key (str): The key to identify the form parameter in
|
135
|
+
the function's signature. This parameter is used to locate and fill
|
136
|
+
the appropriate form according to the assignment. Raises an error
|
137
|
+
if the form parameter key is not found in the function's signature.
|
138
|
+
capacity (int): Capacity for the work log.
|
139
|
+
retry_kwargs (dict): Retry arguments for the function.
|
140
|
+
guidance (str): Guidance or documentation for the function.
|
141
|
+
"""
|
142
|
+
if getattr(self, "work_functions", None) is None:
|
143
|
+
self.work_functions = {}
|
144
|
+
|
145
|
+
if func.__name__ not in self.work_functions:
|
146
|
+
self.work_functions[func.__name__] = WorkFunction(
|
147
|
+
assignment=assignment,
|
148
|
+
function=func,
|
149
|
+
retry_kwargs=retry_kwargs or {},
|
150
|
+
guidance=guidance,
|
151
|
+
capacity=capacity,
|
152
|
+
)
|
153
|
+
|
154
|
+
work_func: WorkFunction = self.work_functions[func.__name__]
|
155
|
+
|
156
|
+
# locate form that should be filled according to the assignment
|
157
|
+
if form_param_key:
|
158
|
+
func_signature = inspect.signature(func)
|
159
|
+
if form_param_key not in func_signature.parameters:
|
160
|
+
raise KeyError(f"Failed to locate form. \"{form_param_key}\" is not defined in the function.")
|
161
|
+
if "self" in func_signature.parameters:
|
162
|
+
bound_args = func_signature.bind(None, *args, **kwargs)
|
163
|
+
else:
|
164
|
+
bound_args = func_signature.bind(*args, **kwargs)
|
165
|
+
bound_args.apply_defaults()
|
166
|
+
arguments = bound_args.arguments
|
167
|
+
|
168
|
+
form_key = arguments.get(form_param_key)
|
169
|
+
try:
|
170
|
+
form_key = get_lion_id(form_key)
|
171
|
+
except:
|
172
|
+
pass
|
173
|
+
form = self.forms.get(form_key) or self.default_form
|
174
|
+
|
175
|
+
if form:
|
176
|
+
subform = form.__class__(assignment=work_func.assignment, task=work_func.guidance)
|
177
|
+
for k in subform.input_fields:
|
178
|
+
v = getattr(form, k, None)
|
179
|
+
setattr(subform, k, v)
|
180
|
+
subform.origin = form
|
181
|
+
kwargs = {"form": subform} | kwargs
|
182
|
+
else:
|
183
|
+
raise ValueError(f"Cannot locate form in Worker's forms and default_form is not available.")
|
184
|
+
|
185
|
+
task = work_func.perform(self, *args, **kwargs)
|
186
|
+
work = Work(async_task=task, async_task_name=work_func.name)
|
187
|
+
await work_func.worklog.append(work)
|
188
|
+
return work
|
189
|
+
|
190
|
+
|
191
|
+
def work(
|
192
|
+
assignment=None,
|
193
|
+
form_param_key=None,
|
194
|
+
capacity=10,
|
195
|
+
guidance=None,
|
196
|
+
retry_kwargs=None,
|
197
|
+
timeout=10,
|
198
|
+
):
|
199
|
+
"""
|
200
|
+
Decorator to mark a method as a work function.
|
201
|
+
|
202
|
+
Args:
|
203
|
+
assignment (str): The assignment description of the work function.
|
204
|
+
form_param_key (str): The key to identify the form parameter in
|
205
|
+
the function's signature. This parameter is used to locate and fill
|
206
|
+
the appropriate form according to the assignment. Raises an error
|
207
|
+
if the form parameter key is not found in the function's signature.
|
208
|
+
capacity (int): Capacity for the work log.
|
209
|
+
guidance (str): Guidance or documentation for the work function.
|
210
|
+
retry_kwargs (dict): Retry arguments for the work function.
|
211
|
+
timeout (int): Timeout for the work function.
|
212
|
+
"""
|
213
|
+
|
214
|
+
def decorator(func):
|
215
|
+
@wraps(func)
|
216
|
+
async def wrapper(
|
217
|
+
self: Worker,
|
218
|
+
*args,
|
219
|
+
func=func,
|
220
|
+
assignment=assignment,
|
221
|
+
form_param_key=form_param_key,
|
222
|
+
capacity=capacity,
|
223
|
+
retry_kwargs=retry_kwargs,
|
224
|
+
guidance=guidance,
|
225
|
+
**kwargs,
|
226
|
+
):
|
227
|
+
retry_kwargs = retry_kwargs or {}
|
228
|
+
retry_kwargs["timeout"] = retry_kwargs.get("timeout", timeout)
|
229
|
+
return await self._wrapper(
|
230
|
+
*args,
|
231
|
+
func=func,
|
232
|
+
assignment=assignment,
|
233
|
+
form_param_key=form_param_key,
|
234
|
+
capacity=capacity,
|
235
|
+
retry_kwargs=retry_kwargs,
|
236
|
+
guidance=guidance,
|
237
|
+
**kwargs,
|
238
|
+
)
|
239
|
+
|
240
|
+
return wrapper
|
241
|
+
|
242
|
+
return decorator
|
243
|
+
|
244
|
+
|
245
|
+
# # Example
|
246
|
+
# from lionagi import Session
|
247
|
+
# from lionagi.experimental.work.work_function import work
|
248
|
+
|
249
|
+
|
250
|
+
# class MyWorker(Worker):
|
251
|
+
|
252
|
+
# @work(assignment="instruction, context -> response")
|
253
|
+
# async def chat(instruction=None, context=None):
|
254
|
+
# session = Session()
|
255
|
+
# return await session.chat(instruction=instruction, context=context)
|
256
|
+
|
257
|
+
|
258
|
+
# await a.chat(instruction="Hello", context={})
|
@@ -0,0 +1,120 @@
|
|
1
|
+
"""
|
2
|
+
Copyright 2024 HaiyangLi
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
"""
|
16
|
+
|
17
|
+
from lionagi.core.collections.abc import Progressable
|
18
|
+
from lionagi.core.collections import pile, progression, Pile
|
19
|
+
from lionagi.core.work.work import Work, WorkStatus
|
20
|
+
from lionagi.core.work.work_queue import WorkQueue
|
21
|
+
|
22
|
+
|
23
|
+
class WorkLog(Progressable):
|
24
|
+
"""
|
25
|
+
A class representing a log of work items.
|
26
|
+
|
27
|
+
Attributes:
|
28
|
+
pile (Pile): A pile containing work items.
|
29
|
+
pending (Progression): A progression of pending work items.
|
30
|
+
queue (WorkQueue): A queue to manage the execution of work items.
|
31
|
+
"""
|
32
|
+
|
33
|
+
def __init__(self, capacity=10, workpile=None):
|
34
|
+
"""
|
35
|
+
Initializes a new instance of WorkLog.
|
36
|
+
|
37
|
+
Args:
|
38
|
+
capacity (int): The capacity of the work queue.
|
39
|
+
workpile (Pile, optional): An optional pile of initial work items.
|
40
|
+
"""
|
41
|
+
self.pile = (
|
42
|
+
workpile if workpile and isinstance(workpile, Pile) else pile({}, Work)
|
43
|
+
)
|
44
|
+
self.pending = progression(workpile) if workpile else progression()
|
45
|
+
self.queue = WorkQueue(capacity=capacity)
|
46
|
+
|
47
|
+
async def append(self, work: Work):
|
48
|
+
"""
|
49
|
+
Appends a new work item to the log.
|
50
|
+
|
51
|
+
Args:
|
52
|
+
work (Work): The work item to append.
|
53
|
+
"""
|
54
|
+
self.pile.append(work)
|
55
|
+
self.pending.append(work)
|
56
|
+
|
57
|
+
async def forward(self):
|
58
|
+
"""
|
59
|
+
Forwards pending work items to the queue.
|
60
|
+
"""
|
61
|
+
while len(self.pending) > 0:
|
62
|
+
work: Work = self.pile[self.pending.popleft()]
|
63
|
+
await self.queue.enqueue(work)
|
64
|
+
|
65
|
+
async def stop(self):
|
66
|
+
"""
|
67
|
+
Stops the work queue.
|
68
|
+
"""
|
69
|
+
await self.queue.stop()
|
70
|
+
|
71
|
+
@property
|
72
|
+
def pending_work(self):
|
73
|
+
"""
|
74
|
+
Retrieves the pile of pending work items.
|
75
|
+
|
76
|
+
Returns:
|
77
|
+
Pile: A pile of pending work items.
|
78
|
+
"""
|
79
|
+
return pile([i for i in self.pile if i.status == WorkStatus.PENDING])
|
80
|
+
|
81
|
+
@property
|
82
|
+
def stopped(self):
|
83
|
+
"""
|
84
|
+
Checks if the work queue is stopped.
|
85
|
+
|
86
|
+
Returns:
|
87
|
+
bool: True if the work queue is stopped, else False.
|
88
|
+
"""
|
89
|
+
return self.queue.stopped
|
90
|
+
|
91
|
+
@property
|
92
|
+
def completed_work(self):
|
93
|
+
"""
|
94
|
+
Retrieves the pile of completed work items.
|
95
|
+
|
96
|
+
Returns:
|
97
|
+
Pile: A pile of completed work items.
|
98
|
+
"""
|
99
|
+
return pile([i for i in self.pile if i.status == WorkStatus.COMPLETED])
|
100
|
+
|
101
|
+
def __contains__(self, work):
|
102
|
+
"""
|
103
|
+
Checks if a work item is in the pile.
|
104
|
+
|
105
|
+
Args:
|
106
|
+
work (Work): The work item to check.
|
107
|
+
|
108
|
+
Returns:
|
109
|
+
bool: True if the work item is in the pile, else False.
|
110
|
+
"""
|
111
|
+
return work in self.pile
|
112
|
+
|
113
|
+
def __iter__(self):
|
114
|
+
"""
|
115
|
+
Returns an iterator over the work pile.
|
116
|
+
|
117
|
+
Returns:
|
118
|
+
Iterator: An iterator over the work pile.
|
119
|
+
"""
|
120
|
+
return iter(self.pile)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
from abc import ABC
|
2
|
+
from lionagi.core.collections import iModel
|
3
|
+
|
4
|
+
|
5
|
+
class TokenCompressor(ABC):
|
6
|
+
"""
|
7
|
+
NOTICE:
|
8
|
+
The token compressor system is inspired by LLMLingua.
|
9
|
+
https://github.com/microsoft/LLMLingua
|
10
|
+
|
11
|
+
MIT License
|
12
|
+
Copyright (c) Microsoft Corporation.
|
13
|
+
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
16
|
+
in the Software without restriction, including without limitation the rights
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
19
|
+
furnished to do so, subject to the following conditions:
|
20
|
+
|
21
|
+
Authors:
|
22
|
+
Huiqiang Jiang, Qianhui Wu, Chin-Yew Lin, Yuqing Yang, Lili Qiu
|
23
|
+
@inproceedings{jiang-etal-2023-llmlingua,
|
24
|
+
title = "{LLML}ingua: Compressing Prompts for Accelerated Inference of Large Language Models",
|
25
|
+
author = "Huiqiang Jiang and Qianhui Wu and Chin-Yew Lin and Yuqing Yang and Lili Qiu",
|
26
|
+
booktitle = "Proceedings of the 2023 Conference on Empirical Methods in Natural Language Processing",
|
27
|
+
month = dec,
|
28
|
+
year = "2023",
|
29
|
+
publisher = "Association for Computational Linguistics",
|
30
|
+
url = "https://aclanthology.org/2023.emnlp-main.825",
|
31
|
+
doi = "10.18653/v1/2023.emnlp-main.825",
|
32
|
+
pages = "13358--13376",
|
33
|
+
}
|
34
|
+
|
35
|
+
LionAGI Modifications:
|
36
|
+
- Only borrowed the concept of token compression via perplexity
|
37
|
+
- Removed the dependency on the LLMLingua library
|
38
|
+
- use logprobs from GPT model to calculate perplexity
|
39
|
+
- added async ability to the functions
|
40
|
+
- used lionagi existing iModel class for API calls
|
41
|
+
"""
|
42
|
+
|
43
|
+
def __init__(self, imodel: iModel, tokenizer=None, splitter=None):
|
44
|
+
self.imodel = imodel
|
45
|
+
self.tokenizer = tokenizer
|
46
|
+
self.splitter = splitter
|