lionagi 0.6.0__py3-none-any.whl → 0.7.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.
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