lionagi 0.6.0__py3-none-any.whl → 0.7.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. lionagi/__init__.py +2 -0
  2. lionagi/libs/token_transform/__init__.py +0 -0
  3. lionagi/libs/token_transform/llmlingua.py +1 -0
  4. lionagi/libs/token_transform/perplexity.py +439 -0
  5. lionagi/libs/token_transform/synthlang.py +409 -0
  6. lionagi/operations/ReAct/ReAct.py +126 -0
  7. lionagi/operations/ReAct/utils.py +28 -0
  8. lionagi/operations/__init__.py +1 -9
  9. lionagi/operations/_act/act.py +73 -0
  10. lionagi/operations/chat/__init__.py +3 -0
  11. lionagi/operations/chat/chat.py +173 -0
  12. lionagi/operations/communicate/__init__.py +0 -0
  13. lionagi/operations/communicate/communicate.py +167 -0
  14. lionagi/operations/instruct/__init__.py +3 -0
  15. lionagi/operations/instruct/instruct.py +29 -0
  16. lionagi/operations/interpret/__init__.py +3 -0
  17. lionagi/operations/interpret/interpret.py +40 -0
  18. lionagi/operations/operate/__init__.py +3 -0
  19. lionagi/operations/operate/operate.py +189 -0
  20. lionagi/operations/parse/__init__.py +3 -0
  21. lionagi/operations/parse/parse.py +125 -0
  22. lionagi/operations/plan/plan.py +3 -3
  23. lionagi/operations/select/__init__.py +0 -4
  24. lionagi/operations/select/select.py +11 -30
  25. lionagi/operations/select/utils.py +13 -2
  26. lionagi/operations/translate/__init__.py +0 -0
  27. lionagi/operations/translate/translate.py +47 -0
  28. lionagi/operations/types.py +25 -3
  29. lionagi/operatives/action/function_calling.py +1 -1
  30. lionagi/operatives/action/manager.py +22 -26
  31. lionagi/operatives/action/tool.py +1 -1
  32. lionagi/operatives/strategies/__init__.py +3 -0
  33. lionagi/{operations → operatives}/strategies/params.py +18 -2
  34. lionagi/protocols/adapters/__init__.py +0 -0
  35. lionagi/protocols/adapters/adapter.py +95 -0
  36. lionagi/protocols/adapters/json_adapter.py +101 -0
  37. lionagi/protocols/adapters/pandas_/__init__.py +0 -0
  38. lionagi/protocols/adapters/pandas_/csv_adapter.py +50 -0
  39. lionagi/protocols/adapters/pandas_/excel_adapter.py +52 -0
  40. lionagi/protocols/adapters/pandas_/pd_dataframe_adapter.py +31 -0
  41. lionagi/protocols/adapters/pandas_/pd_series_adapter.py +17 -0
  42. lionagi/protocols/adapters/types.py +18 -0
  43. lionagi/protocols/generic/pile.py +22 -1
  44. lionagi/protocols/graph/node.py +17 -1
  45. lionagi/protocols/types.py +3 -3
  46. lionagi/service/__init__.py +1 -14
  47. lionagi/service/endpoints/base.py +1 -1
  48. lionagi/service/endpoints/rate_limited_processor.py +2 -1
  49. lionagi/service/manager.py +1 -1
  50. lionagi/service/types.py +18 -0
  51. lionagi/session/branch.py +1098 -929
  52. lionagi/version.py +1 -1
  53. {lionagi-0.6.0.dist-info → lionagi-0.7.0.dist-info}/METADATA +4 -4
  54. {lionagi-0.6.0.dist-info → lionagi-0.7.0.dist-info}/RECORD +66 -38
  55. lionagi/libs/compress/models.py +0 -66
  56. lionagi/libs/compress/utils.py +0 -69
  57. lionagi/operations/select/prompt.py +0 -5
  58. lionagi/protocols/_adapter.py +0 -224
  59. /lionagi/{libs/compress → operations/ReAct}/__init__.py +0 -0
  60. /lionagi/operations/{strategies → _act}/__init__.py +0 -0
  61. /lionagi/{operations → operatives}/strategies/base.py +0 -0
  62. /lionagi/{operations → operatives}/strategies/concurrent.py +0 -0
  63. /lionagi/{operations → operatives}/strategies/concurrent_chunk.py +0 -0
  64. /lionagi/{operations → operatives}/strategies/concurrent_sequential_chunk.py +0 -0
  65. /lionagi/{operations → operatives}/strategies/sequential.py +0 -0
  66. /lionagi/{operations → operatives}/strategies/sequential_chunk.py +0 -0
  67. /lionagi/{operations → operatives}/strategies/sequential_concurrent_chunk.py +0 -0
  68. /lionagi/{operations → operatives}/strategies/utils.py +0 -0
  69. {lionagi-0.6.0.dist-info → lionagi-0.7.0.dist-info}/WHEEL +0 -0
  70. {lionagi-0.6.0.dist-info → lionagi-0.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,409 @@
1
+ # synthlang.py
2
+ """
3
+ SynthLang translator and system prompt generator.
4
+ We incorporate the simpler framework approach (a list of frameworks to enable),
5
+ and rely on a chosen template from the included FRAMEWORK_TEMPLATES.
6
+ We also integrate optional perplexity compression from `compress_perplexity.py`.
7
+ """
8
+ # For the optional compression step:
9
+ from timeit import default_timer as timer
10
+ from typing import Literal
11
+
12
+ from lionagi.session.branch import Branch
13
+ from lionagi.settings import Settings
14
+
15
+ from .perplexity import compress_text, iModel
16
+
17
+ ########################################################################
18
+ # 1) Template Data
19
+ # Each item is a dictionary capturing your multi-line text blocks.
20
+ ########################################################################
21
+
22
+ group_theory = {
23
+ "title": "Group Theory Analysis",
24
+ "domain": "mathematics",
25
+ "category": "Abstract Algebra",
26
+ "overview": "Investigation of algebraic structures using group theory and ring theory.",
27
+ "content": """# Structures
28
+ Let G be a group with operation •
29
+ Let H be a subgroup of G
30
+ Let N be a normal subgroup of G
31
+
32
+ # Properties
33
+ P(x): "x is a homomorphism"
34
+ Q(x): "x preserves group structure"
35
+ R(x): "x maps to kernel"
36
+
37
+ # Objectives
38
+ 1. Prove fundamental homomorphism theorem
39
+ 2. Show group action properties
40
+ 3. Analyze quotient groups
41
+ """,
42
+ }
43
+
44
+ category_theory = {
45
+ "title": "Category Theory Concepts",
46
+ "domain": "mathematics",
47
+ "category": "Category Theory",
48
+ "overview": "Abstract mathematical framework dealing with relationships between structures.",
49
+ "content": """# Basic Definitions
50
+ C = (Ob(C), hom(C), ∘)
51
+ F: C → D (Functor)
52
+ ...
53
+ """,
54
+ }
55
+
56
+ complex_analysis = {
57
+ "title": "Complex Analysis Foundations",
58
+ "domain": "mathematics",
59
+ "category": "Complex Analysis",
60
+ "overview": "Advanced study of complex functions, including integration and residue theory.",
61
+ "content": """# Complex Integration
62
+ ∮ f(z)dz = 2πi∑Res(f,ak)
63
+ ...
64
+ """,
65
+ }
66
+
67
+ math_logic = {
68
+ "title": "Mathematical Logic Foundations",
69
+ "domain": "mathematics",
70
+ "category": "Mathematical Logic",
71
+ "overview": "Exploration of fundamental mathematical logic concepts.",
72
+ "content": """# Sets and Axioms
73
+ Let A be the set of all propositions.
74
+ ...
75
+ """,
76
+ }
77
+
78
+ number_theory = {
79
+ "title": "Number Theory Principles",
80
+ "domain": "mathematics",
81
+ "category": "Number Theory",
82
+ "overview": "Study of integers, prime numbers, and arithmetic functions.",
83
+ "content": """# Congruence Relations
84
+ a ≡ b (mod n)
85
+ ...
86
+ """,
87
+ }
88
+
89
+ set_theory = {
90
+ "title": "Set Theory Foundations",
91
+ "domain": "mathematics",
92
+ "category": "Set Theory",
93
+ "overview": "Exploration of fundamental set theory concepts and operations.",
94
+ "content": """# Basic Definitions
95
+ Let U be the universal set
96
+ ...
97
+ """,
98
+ }
99
+
100
+ symbolic_systems = {
101
+ "title": "Symbolic Systems Analysis",
102
+ "domain": "computer-science",
103
+ "category": "Symbolic Systems",
104
+ "overview": "Analysis of symbolic computation in AI and formal languages.",
105
+ "content": """# Core Concepts
106
+ Let Σ be a finite alphabet
107
+ ...
108
+ """,
109
+ }
110
+
111
+ symbolic_exploration_system_supression = {
112
+ "title": "Systematic Suppression Exploration",
113
+ "domain": "societal",
114
+ "category": "Real-World Simulations",
115
+ "overview": "Analysis of suppression mechanisms using symbolic logic.",
116
+ "content": """# Sets and Categories
117
+ Let U be the set of actions representing policies ...
118
+ """,
119
+ }
120
+
121
+ topology_fundamentals = {
122
+ "title": "Topology Fundamentals",
123
+ "domain": "mathematics",
124
+ "category": "Topology",
125
+ "overview": "Study of geometric properties under continuous deformations.",
126
+ "content": """# Open Sets
127
+ (X,τ) topological space
128
+ ...
129
+ """,
130
+ }
131
+
132
+ FRAMEWORK_TEMPLATES = {
133
+ "group_theory": group_theory,
134
+ "category_theory": category_theory,
135
+ "complex_analysis": complex_analysis,
136
+ "math_logic": math_logic,
137
+ "number_theory": number_theory,
138
+ "set_theory": set_theory,
139
+ "symbolic_systems": symbolic_systems,
140
+ "symbolic_exploration_system_supression": symbolic_exploration_system_supression,
141
+ "topology_fundamentals": topology_fundamentals,
142
+ }
143
+
144
+
145
+ ########################################################################
146
+ # 2) Framework Definitions (Simplified)
147
+ ########################################################################
148
+
149
+ # Instead of a complex dict with "selectedGlyphs", let's do a simpler approach:
150
+ # We define each "framework" by name, description, and glyphs. The user can pick them by name.
151
+ FRAMEWORK_OPTIONS = {
152
+ "math": {
153
+ "name": "Mathematical Framework",
154
+ "description": "Offers a suite of math glyphs and notation rules.",
155
+ "glyphs": [
156
+ {
157
+ "symbol": "↹",
158
+ "name": "Focus/Filter",
159
+ "description": "Used for focusing instructions",
160
+ },
161
+ {
162
+ "symbol": "Σ",
163
+ "name": "Summarize",
164
+ "description": "Condense large sets of data",
165
+ },
166
+ {
167
+ "symbol": "⊕",
168
+ "name": "Combine/Merge",
169
+ "description": "Merge multiple data sources",
170
+ },
171
+ {
172
+ "symbol": "•",
173
+ "name": "Group Operation",
174
+ "description": "Binary operation in group theory",
175
+ },
176
+ ],
177
+ },
178
+ "optim": {
179
+ "name": "Optimization Framework",
180
+ "description": "Compression and optimization for code/math expressions.",
181
+ "glyphs": [
182
+ {
183
+ "symbol": "IF",
184
+ "name": "Conditional Operator",
185
+ "description": "Represents branching logic",
186
+ }
187
+ ],
188
+ },
189
+ "custom_algebra": {
190
+ "name": "Custom Algebraic Framework",
191
+ "description": "Extra rules for ring, group, field expansions.",
192
+ "glyphs": [
193
+ {
194
+ "symbol": "∞",
195
+ "name": "Infinite Operator",
196
+ "description": "Represents unbounded algebraic ops",
197
+ }
198
+ ],
199
+ },
200
+ }
201
+
202
+ ########################################################################
203
+ # 3) SynthLang Base Prompt
204
+ ########################################################################
205
+
206
+ BASE_PROMPT = """You are a SynthLang translator. You convert standard text into SynthLang format with these rules:
207
+
208
+ [Framework Integration]
209
+ - Use relevant framework glyphs wherever possible.
210
+ - Combine multiple frameworks if requested.
211
+
212
+ [Grammar Rules]
213
+ 1) Task Glyphs:
214
+ - ↹ (Focus/Filter) for main tasks
215
+ - Σ (Summarize) for condensing info
216
+ - ⊕ (Combine) for merging data
217
+ - ? (Query) for clarifications
218
+ - IF for conditionals
219
+
220
+ 2) Subject Markers:
221
+ - Use • before datasets (e.g., •myData)
222
+ - Use 花 for abstract concepts
223
+ - Use 山 for hierarchical structures
224
+
225
+ 3) Modifiers:
226
+ - ^format(type) for output format
227
+ - ^n for importance level
228
+ - ^lang for language
229
+ - ^t{n} for time constraints
230
+
231
+ 4) Flow Control:
232
+ - [p=n] for priority
233
+ - -> for sequential
234
+ - + for parallel
235
+ - | for alternatives
236
+
237
+ [Output Style]
238
+ - Maximize compression by removing articles & filler
239
+ - Use glyphs for repeated phrases
240
+ - Preserve semantic meaning
241
+ """
242
+
243
+
244
+ ########################################################################
245
+ # 4) Utility to build the "Active Frameworks" block
246
+ ########################################################################
247
+
248
+
249
+ def build_frameworks_text(frameworks: list[str]) -> str:
250
+ """
251
+ Takes a list of framework keys (e.g. ["math", "optim"]) and returns
252
+ a textual block describing them.
253
+ """
254
+ lines = []
255
+ if not frameworks:
256
+ frameworks = FRAMEWORK_OPTIONS.keys()
257
+
258
+ for fw_key in frameworks:
259
+ fw = FRAMEWORK_OPTIONS.get(fw_key, None)
260
+ if fw:
261
+ lines.append(f"{fw['name']}: {fw['description']}")
262
+ lines.append("Glyphs:")
263
+ for g in fw["glyphs"]:
264
+ lines.append(
265
+ f" {g['symbol']} -> {g['name']} ({g['description']})"
266
+ )
267
+ lines.append("")
268
+ return "\n".join(lines).strip()
269
+
270
+
271
+ ########################################################################
272
+ # 5) Main: create the SynthLang prompt
273
+ ########################################################################
274
+
275
+
276
+ def create_synthlang_system_prompt(
277
+ template_name: Literal[
278
+ "group_theory",
279
+ "category_theory",
280
+ "complex_analysis",
281
+ "math_logic",
282
+ "number_theory",
283
+ "set_theory",
284
+ "symbolic_systems",
285
+ "symbolic_exploration_system_supression",
286
+ "topology_fundamentals",
287
+ ],
288
+ frameworks: list[str],
289
+ additional_text: str = "",
290
+ ) -> str:
291
+ """
292
+ Merges:
293
+ - BASE_PROMPT
294
+ - "Active Frameworks" block (from frameworks list)
295
+ - The chosen template (from FRAMEWORK_TEMPLATES)
296
+ - plus additional text if desired
297
+ """
298
+ template_block = FRAMEWORK_TEMPLATES[template_name]
299
+ frameworks_text = build_frameworks_text(frameworks)
300
+
301
+ # We show the user the "domain", "category", etc. from the template
302
+ template_details = (
303
+ f"Title: {template_block['title']}\n"
304
+ f"Domain: {template_block['domain']}\n"
305
+ f"Category: {template_block['category']}\n"
306
+ f"Overview: {template_block['overview']}\n"
307
+ "Excerpt:\n"
308
+ f"{template_block['content']}\n"
309
+ )
310
+
311
+ prompt = (
312
+ f"{BASE_PROMPT}\n\n"
313
+ "[Active Frameworks]\n"
314
+ f"{frameworks_text}\n\n"
315
+ "[Template]\n"
316
+ f"{template_details}\n"
317
+ )
318
+
319
+ if additional_text.strip():
320
+ prompt += f"\n[Additional]\n{additional_text.strip()}\n"
321
+
322
+ # Usually you might want the entire final text to be the system instruction:
323
+ return prompt
324
+
325
+
326
+ ########################################################################
327
+ # 6) Translate text into SynthLang format
328
+ ########################################################################
329
+
330
+
331
+ # TODO: refactor using SynthLang package
332
+ async def translate_to_synthlang(
333
+ text: str,
334
+ template_name: str = "symbolic_systems",
335
+ frameworks: list[str] = None,
336
+ compress: bool = False,
337
+ chat_model: iModel = None,
338
+ compress_model: iModel = None,
339
+ compression_ratio: float = 0.2,
340
+ compress_kwargs=None,
341
+ verbose: bool = True,
342
+ branch: Branch = None,
343
+ **kwargs,
344
+ ) -> str:
345
+ """
346
+ Optionally compress the input text using perplexity, then build a final
347
+ "SynthLang" style system prompt that includes frameworks, templates, etc.
348
+
349
+ :param text: The original text to be translated/compressed
350
+ :param template_name: Key in FRAMEWORK_TEMPLATES
351
+ :param frameworks: e.g. ["math", "optim"] to enable these frameworks
352
+ :param compress: If True, uses perplexity-based compression
353
+ :param chat_model: The model for perplexity compression
354
+ :param compression_ratio: float ratio of final token usage
355
+ :param compress_kwargs: Additional arguments to pass to compression
356
+ :return: A string in SynthLang style
357
+ """
358
+ from .synthlang import create_synthlang_system_prompt
359
+
360
+ start = timer()
361
+ chat_model = chat_model or iModel(**Settings.iModel.CHAT)
362
+ if compress:
363
+ text = await compress_text(
364
+ text,
365
+ chat_model=compress_model or chat_model,
366
+ target_ratio=compression_ratio,
367
+ **(compress_kwargs or {}),
368
+ )
369
+
370
+ # Build final system prompt
371
+ final_prompt = create_synthlang_system_prompt(
372
+ template_name=template_name,
373
+ frameworks=frameworks,
374
+ )
375
+
376
+ sys1 = None
377
+ sys2 = final_prompt
378
+ if branch and branch.system:
379
+ sys1 = branch.system
380
+ branch.msgs.add_message(system=sys2)
381
+
382
+ else:
383
+ branch = Branch(system=final_prompt, chat_model=chat_model)
384
+
385
+ from lionagi.service.endpoints.token_calculator import TokenCalculator
386
+
387
+ calculator = TokenCalculator()
388
+
389
+ len_tokens = calculator.tokenize(text, return_tokens=False)
390
+ out = await branch.communicate(
391
+ instruction=f"Converts the given text into SynthLang's hyper-efficient format.",
392
+ context="Text to convert:\n\n" + text,
393
+ guidance=f"Following SynthLang, translate the provided text into SynthLang syntax. Shrink the token size by 60-85%. Return only the translated text.",
394
+ **kwargs,
395
+ )
396
+ if sys1:
397
+ branch.msgs.add_message(system=sys1)
398
+
399
+ len_ = calculator.tokenize(out, return_tokens=False)
400
+ if verbose:
401
+ msg = ""
402
+ msg += f"Compression Method: SynthLang\n"
403
+ msg += f"Compressed Token number: {len_}\n"
404
+ msg += f"Token Compression Ratio: {len_ / len_tokens:.1%}\n"
405
+ msg += f"Compression Time: {timer() - start:.03f} seconds\n"
406
+ msg += f"Compression Model: {branch.chat_model.model_name}\n"
407
+ print(msg)
408
+
409
+ return out
@@ -0,0 +1,126 @@
1
+ # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import logging
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ from pydantic import BaseModel
9
+
10
+ from lionagi.operatives.types import Instruct
11
+ from lionagi.service.imodel import iModel
12
+ from lionagi.utils import copy
13
+
14
+ if TYPE_CHECKING:
15
+ from lionagi.session.branch import Branch
16
+
17
+
18
+ async def ReAct(
19
+ branch: "Branch",
20
+ instruct: Instruct | dict[str, Any],
21
+ interpret: bool = False,
22
+ tools: Any = None,
23
+ tool_schemas: Any = None,
24
+ response_format: type[BaseModel] = None,
25
+ extension_allowed: bool = False,
26
+ max_extensions: int | None = None,
27
+ response_kwargs: dict | None = None,
28
+ return_analysis: bool = False,
29
+ analysis_model: iModel | None = None,
30
+ **kwargs,
31
+ ):
32
+ # If no tools or tool schemas are provided, default to "all tools"
33
+ if not tools and not tool_schemas:
34
+ tools = True
35
+
36
+ # Possibly interpret the instruction to refine it
37
+ instruction_str = None
38
+ if interpret:
39
+ instruction_str = await branch.interpret(
40
+ str(
41
+ instruct.to_dict()
42
+ if isinstance(instruct, Instruct)
43
+ else instruct
44
+ )
45
+ )
46
+
47
+ # Convert Instruct to dict if necessary
48
+ instruct_dict = (
49
+ instruct.to_dict()
50
+ if isinstance(instruct, Instruct)
51
+ else dict(instruct)
52
+ )
53
+ # Overwrite the "instruction" field with the interpreted string (if any)
54
+ instruct_dict["instruction"] = instruction_str or instruct_dict.get(
55
+ "instruction"
56
+ )
57
+
58
+ # Prepare a copy of user-provided kwargs for the first operate call
59
+ kwargs_for_operate = copy(kwargs)
60
+ kwargs_for_operate["actions"] = True
61
+ kwargs_for_operate["reason"] = True
62
+
63
+ # We'll pass the refined instruct_dict plus the user’s other kwargs
64
+ from .utils import ReActAnalysis
65
+
66
+ # Step 1: Generate initial ReAct analysis
67
+ analysis: ReActAnalysis = await branch.operate(
68
+ response_format=ReActAnalysis,
69
+ tools=tools,
70
+ tool_schemas=tool_schemas,
71
+ chat_model=analysis_model or branch.chat_model,
72
+ **kwargs_for_operate,
73
+ )
74
+ analyses = [analysis]
75
+
76
+ # Validate and clamp max_extensions if needed
77
+ if max_extensions and max_extensions > 5:
78
+ logging.warning("max_extensions should not exceed 5; defaulting to 5.")
79
+ max_extensions = 5
80
+
81
+ # Step 2: Possibly loop through expansions if extension_needed
82
+ extensions = max_extensions
83
+ while (
84
+ extension_allowed
85
+ and analysis.extension_needed
86
+ and (extensions if extensions else 1) > 0
87
+ ):
88
+ new_instruction = None
89
+ if extensions == max_extensions:
90
+ new_instruction = ReActAnalysis.FIRST_EXT_PROMPT.format(
91
+ extensions=extensions
92
+ )
93
+ else:
94
+ new_instruction = ReActAnalysis.CONTINUE_EXT_PROMPT.format(
95
+ extensions=extensions
96
+ )
97
+
98
+ # Each expansion uses a fresh copy of instruct_dict + forcibly "reason" + "actions"
99
+ expanded_kwargs = copy(instruct_dict)
100
+ expanded_kwargs["instruction"] = new_instruction
101
+ expanded_kwargs["reason"] = True
102
+ expanded_kwargs["actions"] = True
103
+
104
+ analysis = await branch.operate(
105
+ response_format=ReActAnalysis,
106
+ tools=tools,
107
+ tool_schemas=tool_schemas,
108
+ **expanded_kwargs,
109
+ )
110
+ analyses.append(analysis)
111
+
112
+ if extensions:
113
+ extensions -= 1
114
+
115
+ # Step 3: Produce final answer by calling branch._instruct with an answer prompt
116
+ answer_prompt = ReActAnalysis.ANSWER_PROMPT.format(
117
+ instruction=instruct_dict["instruction"]
118
+ )
119
+ out = await branch.communicate(
120
+ instruction=answer_prompt,
121
+ response_format=response_format,
122
+ **(response_kwargs or {}),
123
+ )
124
+ if return_analysis:
125
+ return out, analyses
126
+ return out
@@ -0,0 +1,28 @@
1
+ # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from typing import ClassVar
6
+
7
+ from pydantic import BaseModel, Field
8
+
9
+
10
+ class ReActAnalysis(BaseModel):
11
+
12
+ FIRST_EXT_PROMPT: ClassVar[str] = (
13
+ "You are provided with another round to perform reason action to provide an accurate final answer. you have max another {extensions} rounds, set extension_needed to False if you are done and ready to provide final answer."
14
+ )
15
+
16
+ CONTINUE_EXT_PROMPT: ClassVar[str] = (
17
+ "You are provided with another round, you have max another {extensions} rounds"
18
+ )
19
+
20
+ ANSWER_PROMPT: ClassVar[str] = (
21
+ "given above reason and actions, please provide final answer to the original user request {instruction}"
22
+ )
23
+
24
+ analysis: str
25
+ extension_needed: bool = Field(
26
+ False,
27
+ description="Set to True if more steps are needed to provide an accurate answer. If True, additional rounds are allowed.",
28
+ )
@@ -2,12 +2,4 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
- from .brainstorm.brainstorm import brainstorm
6
- from .plan.plan import plan
7
- from .select.select import select
8
-
9
- __all__ = (
10
- "brainstorm",
11
- "plan",
12
- "select",
13
- )
5
+ from .types import *
@@ -0,0 +1,73 @@
1
+ # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import logging
6
+ from typing import TYPE_CHECKING
7
+
8
+ from pydantic import BaseModel
9
+
10
+ from lionagi.protocols.types import ActionResponse, Log
11
+
12
+ if TYPE_CHECKING:
13
+ from lionagi.session.branch import Branch
14
+
15
+
16
+ async def _act(
17
+ branch: "Branch",
18
+ action_request: BaseModel | dict,
19
+ suppress_errors: bool = False,
20
+ ) -> ActionResponse:
21
+
22
+ _request = {}
23
+
24
+ if isinstance(action_request, BaseModel):
25
+ if hasattr(action_request, "function") and hasattr(
26
+ action_request, "arguments"
27
+ ):
28
+ _request["function"] = action_request.function
29
+ _request["arguments"] = action_request.arguments
30
+ elif isinstance(action_request, dict):
31
+ if {"function", "arguments"} <= set(action_request.keys()):
32
+ _request["function"] = action_request["function"]
33
+ _request["arguments"] = action_request["arguments"]
34
+
35
+ try:
36
+ func_call = await branch._action_manager.invoke(_request)
37
+ except Exception as e:
38
+ branch._log_manager.log(Log(content={"error": str(e)}))
39
+ if suppress_errors:
40
+ logging.error(
41
+ f"Error invoking action '{_request['function']}': {e}"
42
+ )
43
+ return None
44
+ raise e
45
+
46
+ branch._log_manager.log(Log.create(func_call))
47
+
48
+ from lionagi.protocols.types import ActionRequest
49
+
50
+ if not isinstance(action_request, ActionRequest):
51
+ action_request = ActionRequest.create(
52
+ sender=branch.id,
53
+ recipient=func_call.func_tool.id,
54
+ **_request,
55
+ )
56
+
57
+ # Add the action request/response to the message manager, if not present
58
+ if action_request not in branch.messages:
59
+ branch.msgs.add_message(action_request=action_request)
60
+
61
+ branch.msgs.add_message(
62
+ action_request=action_request,
63
+ action_output=func_call.response,
64
+ )
65
+
66
+ # Return an ActionResponse object
67
+ from lionagi.operatives.types import ActionResponseModel
68
+
69
+ return ActionResponseModel(
70
+ function=action_request.function,
71
+ arguments=action_request.arguments,
72
+ output=func_call.response,
73
+ )
@@ -0,0 +1,3 @@
1
+ # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0