lionagi 0.10.1__py3-none-any.whl → 0.10.3__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 (33) hide show
  1. lionagi/_types.py +1 -0
  2. lionagi/adapters/toml_adapter.py +1 -1
  3. lionagi/fields/__init__.py +29 -0
  4. lionagi/{libs/fields → fields}/action.py +0 -2
  5. lionagi/fields/base.py +151 -0
  6. lionagi/{libs/fields → fields}/file.py +71 -40
  7. lionagi/{libs/fields → fields}/instruct.py +1 -3
  8. lionagi/{libs/fields → fields}/reason.py +4 -19
  9. lionagi/libs/package/imports.py +17 -162
  10. lionagi/libs/token_transform/synthlang_/base.py +1 -1
  11. lionagi/libs/token_transform/synthlang_/resources/frameworks/framework_options.json +1 -1
  12. lionagi/libs/token_transform/synthlang_/resources/mapping/lion_emoji_mapping.toml +1 -1
  13. lionagi/libs/token_transform/synthlang_/resources/mapping/python_math_mapping.toml +1 -1
  14. lionagi/libs/token_transform/synthlang_/resources/mapping/rust_chinese_mapping.toml +1 -1
  15. lionagi/operations/ReAct/ReAct.py +1 -1
  16. lionagi/operations/ReAct/utils.py +36 -15
  17. lionagi/operations/_act/act.py +1 -1
  18. lionagi/operations/brainstorm/brainstorm.py +1 -1
  19. lionagi/operations/instruct/instruct.py +1 -1
  20. lionagi/operations/operate/operate.py +1 -1
  21. lionagi/operations/plan/plan.py +1 -1
  22. lionagi/operations/select/select.py +1 -1
  23. lionagi/operations/utils.py +1 -1
  24. lionagi/protocols/action/manager.py +1 -1
  25. lionagi/protocols/operatives/step.py +2 -2
  26. lionagi/session/branch.py +6 -60
  27. lionagi/utils.py +214 -0
  28. lionagi/version.py +1 -1
  29. {lionagi-0.10.1.dist-info → lionagi-0.10.3.dist-info}/METADATA +3 -3
  30. {lionagi-0.10.1.dist-info → lionagi-0.10.3.dist-info}/RECORD +32 -31
  31. lionagi/libs/fields/__init__.py +0 -36
  32. {lionagi-0.10.1.dist-info → lionagi-0.10.3.dist-info}/WHEEL +0 -0
  33. {lionagi-0.10.1.dist-info → lionagi-0.10.3.dist-info}/licenses/LICENSE +0 -0
lionagi/_types.py CHANGED
@@ -1 +1,2 @@
1
+ from .fields import *
1
2
  from .protocols.types import *
@@ -141,7 +141,7 @@ class TomlFileAdapter(Adapter):
141
141
  dict | list[dict]
142
142
  The loaded data from file.
143
143
  """
144
- with open(obj, "r", encoding="utf-8") as f:
144
+ with open(obj, encoding="utf-8") as f:
145
145
  result = toml.load(f, **kwargs)
146
146
 
147
147
  # Handle array of tables in TOML for "many" case
@@ -0,0 +1,29 @@
1
+ from .action import ActionRequestModel, ActionResponseModel
2
+ from .base import (
3
+ CodeSnippet,
4
+ Outline,
5
+ OutlineItem,
6
+ Section,
7
+ Source,
8
+ TextSnippet,
9
+ )
10
+ from .file import CodeFile, Documentation, File
11
+ from .instruct import Instruct, InstructResponse
12
+ from .reason import Reason
13
+
14
+ __all__ = (
15
+ "ActionRequestModel",
16
+ "ActionResponseModel",
17
+ "Source",
18
+ "TextSnippet",
19
+ "CodeSnippet",
20
+ "Section",
21
+ "OutlineItem",
22
+ "Outline",
23
+ "File",
24
+ "CodeFile",
25
+ "Documentation",
26
+ "Instruct",
27
+ "InstructResponse",
28
+ "Reason",
29
+ )
@@ -16,9 +16,7 @@ from lionagi.utils import to_dict, to_json, to_list
16
16
 
17
17
  __all__ = (
18
18
  "ActionRequestModel",
19
- "ACTION_REQUESTS_FIELD",
20
19
  "ActionResponseModel",
21
- "ACTION_RESPONSES_FIELD",
22
20
  )
23
21
 
24
22
 
lionagi/fields/base.py ADDED
@@ -0,0 +1,151 @@
1
+ from enum import Enum
2
+
3
+ from pydantic import Field, HttpUrl
4
+
5
+ from lionagi.models import HashableModel
6
+
7
+ __all__ = (
8
+ "Source",
9
+ "TextSnippet",
10
+ "CodeSnippet",
11
+ "Section",
12
+ "OutlineItem",
13
+ "Outline",
14
+ )
15
+
16
+
17
+ class Source(HashableModel):
18
+ """
19
+ Represents a citation or external source, such as:
20
+ - a website,
21
+ - documentation link,
22
+ - research paper,
23
+ - or any external resource.
24
+ """
25
+
26
+ title: str = Field(
27
+ ...,
28
+ description="Short label or title for the reference (e.g. 'Pydantic Docs', 'RFC 3986').",
29
+ )
30
+
31
+ url: str | HttpUrl | None = Field(
32
+ None,
33
+ description="Full URL or local path pointing to the resource. Must conform to standard URL format.",
34
+ )
35
+
36
+ note: str | None = Field(
37
+ default=None,
38
+ description=(
39
+ "Optional additional note explaining why this reference is relevant or what it contains."
40
+ ),
41
+ )
42
+
43
+
44
+ class SnippetType(str, Enum):
45
+ TEXT = "text"
46
+ CODE = "code"
47
+
48
+
49
+ class TextSnippet(HashableModel):
50
+ """
51
+ Specialized snippet for textual/prose content.
52
+ """
53
+
54
+ type: SnippetType = Field(
55
+ SnippetType.TEXT,
56
+ description=(
57
+ "Must be 'text' for textual snippets. Ensures explicit type distinction."
58
+ ),
59
+ )
60
+ content: str = Field(
61
+ ...,
62
+ description=(
63
+ "The actual text. Can be a paragraph, bullet list, or any narrative content."
64
+ ),
65
+ )
66
+
67
+
68
+ class CodeSnippet(HashableModel):
69
+ """
70
+ Specialized snippet for source code or command-line examples.
71
+ """
72
+
73
+ type: SnippetType = Field(
74
+ SnippetType.CODE,
75
+ description=(
76
+ "Must be 'code' for code snippets. Allows separate handling or formatting."
77
+ ),
78
+ )
79
+ content: str = Field(
80
+ ...,
81
+ description=(
82
+ "The actual code or command sequence. Should be well-formatted so it can be rendered properly."
83
+ ),
84
+ )
85
+
86
+
87
+ class Section(HashableModel):
88
+ """
89
+ A single section of a document or article. Each section has:
90
+ - A title
91
+ - A sequential list of content snippets (text or code),
92
+ which appear in the intended reading order.
93
+ - Optional sources specifically cited in this section.
94
+ """
95
+
96
+ title: str = Field(
97
+ ...,
98
+ description=(
99
+ "The section heading or label, e.g., 'Introduction', 'Implementation Steps'."
100
+ ),
101
+ )
102
+ snippets: list[TextSnippet | CodeSnippet] = Field(
103
+ default_factory=list,
104
+ description=(
105
+ "Ordered list of content snippets. Could be multiple text blocks, code examples, etc."
106
+ ),
107
+ )
108
+
109
+ sources: list[Source] = Field(
110
+ default_factory=list,
111
+ description=(
112
+ "References specifically cited in this section. "
113
+ "If sources are stored at the doc-level, this can be omitted."
114
+ ),
115
+ )
116
+
117
+
118
+ class OutlineItem(HashableModel):
119
+ """
120
+ Represents a single outline item, which could become a full section later.
121
+ """
122
+
123
+ heading: str = Field(
124
+ ...,
125
+ description="Short name or label for this item, e.g., 'Chapter 1: Basics'.",
126
+ )
127
+ summary: str | None = Field(
128
+ default=None,
129
+ description=(
130
+ "A brief description of what this section will cover, if known."
131
+ ),
132
+ )
133
+
134
+
135
+ class Outline(HashableModel):
136
+ """
137
+ A top-level outline for a document or article.
138
+ Usually used in early planning stages.
139
+ """
140
+
141
+ topic: str = Field(
142
+ ..., description="Working title or overarching topic of the document."
143
+ )
144
+ items: list[OutlineItem] = Field(
145
+ default_factory=list,
146
+ description="List of major outline points or sections planned.",
147
+ )
148
+ notes: str | None = Field(
149
+ default=None,
150
+ description="Any additional remarks, questions, or brainstorming notes for the outline.",
151
+ )
@@ -1,26 +1,29 @@
1
1
  from pathlib import Path
2
2
 
3
- from pydantic import BaseModel, Field, field_validator
3
+ from pydantic import Field, field_validator
4
4
 
5
- from lionagi.models import FieldModel
5
+ from .base import HashableModel, Source
6
6
 
7
-
8
- class Source(BaseModel):
9
- title: str | None = None
10
- url: str | None = None
7
+ __all__ = (
8
+ "File",
9
+ "CodeFile",
10
+ "Documentation",
11
+ )
11
12
 
12
13
 
13
- class File(BaseModel):
14
+ class File(HashableModel):
14
15
  """
15
- Represents a generic file with an optional name, content, and brief description.
16
- Useful for capturing and validating metadata about any kind of file within a project.
16
+ Represents a generic file with an optional name, content, and brief
17
+ description. Useful for capturing and validating metadata about any
18
+ kind of file within a project.
17
19
  """
18
20
 
19
21
  file_name: str | None = Field(
20
22
  default=None,
21
23
  description=(
22
- "Provide the name of the file or its relative path in the project. "
23
- "If an absolute path is given, it will be converted to a string. "
24
+ "Provide the name of the file or its relative path in the "
25
+ "project. If an absolute path is given, it will be converted"
26
+ " to a string. "
24
27
  ),
25
28
  examples=[
26
29
  "session.py",
@@ -32,8 +35,8 @@ class File(BaseModel):
32
35
  default=None,
33
36
  description=(
34
37
  "Paste or generate the full textual content of the file here. "
35
- "For example, this might include plain text, Markdown, or any other text format.\n"
36
- "Examples:\n"
38
+ "For example, this might include plain text, Markdown, or any "
39
+ "other text format.\nExamples:\n"
37
40
  " - '# My Title\\nSome description...'\n"
38
41
  " - 'function greet() { return \"Hello\"; }'"
39
42
  ),
@@ -41,8 +44,9 @@ class File(BaseModel):
41
44
  description: str | None = Field(
42
45
  default=None,
43
46
  description=(
44
- "Briefly explain the file's purpose or function within the project. "
45
- "This can be a short summary describing why this file exists or what it does.\n"
47
+ "Briefly explain the file's purpose or function within the "
48
+ "project. This can be a short summary describing why this "
49
+ "file is needed and/or what it does."
46
50
  ),
47
51
  examples=[
48
52
  "Manages user session logic for the LionAGI framework.",
@@ -56,6 +60,38 @@ class File(BaseModel):
56
60
  return str(value)
57
61
  return value
58
62
 
63
+ def render_content(
64
+ self,
65
+ header: str | None = None,
66
+ footer: str | None = None,
67
+ ) -> str:
68
+ text = f"\n{header}\n\n" if header else ""
69
+ text += self.content if self.content else ""
70
+ if not footer:
71
+ return text
72
+ return text + f"\n\n{footer}\n"
73
+
74
+ def persist(
75
+ self,
76
+ directory: Path | str,
77
+ overwrite: bool = True,
78
+ timestamp: bool = False,
79
+ random_hash_digits: int = None,
80
+ header: str | None = None,
81
+ footer: str | None = None,
82
+ ) -> Path:
83
+ from lionagi.utils import create_path
84
+
85
+ fp = create_path(
86
+ directory=directory,
87
+ filename=self.file_name,
88
+ file_exist_ok=overwrite,
89
+ timestamp=timestamp,
90
+ random_hash_digits=random_hash_digits,
91
+ )
92
+ fp.write_text(self.render_content(header=header, footer=footer))
93
+ return fp
94
+
59
95
 
60
96
  class CodeFile(File):
61
97
  """
@@ -83,7 +119,7 @@ class CodeFile(File):
83
119
  default=None,
84
120
  description=(
85
121
  "Provide or generate the **full source code**. This should be the primary text content "
86
- "of the code file, including all function/class definitions.\n"
122
+ "of the code file, including all function/class definitions.\nNo md codeblock, only raw code"
87
123
  ),
88
124
  examples=[
89
125
  'def my_function():\\n print("Hello, world!")',
@@ -112,10 +148,6 @@ class Documentation(File):
112
148
  "Provide the primary Markdown (or similar) content for the documentation. "
113
149
  "This can include headings, bullet points, tables, code snippets, etc.\n"
114
150
  ),
115
- examples=[
116
- "# Getting Started\\nThis guide walks you through ...",
117
- "# API Reference\\n## Session Class\\n...",
118
- ],
119
151
  )
120
152
  sources: list[Source] | None = Field(
121
153
  default=None,
@@ -125,23 +157,22 @@ class Documentation(File):
125
157
  ),
126
158
  )
127
159
 
128
-
129
- FILE_FIELD = FieldModel(
130
- name="file",
131
- annotation=File | None,
132
- default=None,
133
- )
134
-
135
- CODE_FILE_FIELD = FieldModel(
136
- name="code_file",
137
- annotation=CodeFile | None,
138
- default=None,
139
- )
140
-
141
- DOCUMENTATION_FIELD = FieldModel(
142
- name="documentation",
143
- annotation=Documentation | None,
144
- default=None,
145
- )
146
-
147
- # File: lionagi/libs/fields/file.py
160
+ def render_content(
161
+ self,
162
+ header: str | None = None,
163
+ footer: str | None = None,
164
+ include_source: bool = False,
165
+ ) -> str:
166
+ """
167
+ Renders the documentation content, optionally including citations for sources.
168
+ """
169
+ footer = footer or ""
170
+ if include_source and self.sources:
171
+ footer = "\n\n## Sources\n"
172
+ for source in self.sources:
173
+ footer += f"- [{source.title}]({source.url})\n"
174
+ footer += f" - {source.note}\n" if source.note else ""
175
+ return super().render_content(header=header, footer=footer)
176
+
177
+
178
+ # File: lionagi/fields/file.py
@@ -16,8 +16,6 @@ from lionagi.utils import to_num
16
16
  __all__ = (
17
17
  "Instruct",
18
18
  "InstructResponse",
19
- "INSTRUCT_FIELD",
20
- "LIST_INSTRUCT_FIELD",
21
19
  )
22
20
 
23
21
 
@@ -150,4 +148,4 @@ LIST_INSTRUCT_FIELD_MODEL = FieldModel(
150
148
  default=None,
151
149
  )
152
150
 
153
- # File: lionagi/libs/fields/instruct.py
151
+ # File: lionagi/fields/instruct.py
@@ -7,12 +7,7 @@ from pydantic import BaseModel, Field, field_validator
7
7
  from lionagi.models import FieldModel
8
8
  from lionagi.utils import to_num
9
9
 
10
- __all__ = (
11
- "Reason",
12
- "REASON_FIELD",
13
- "CONFIDENCE_SCORE_FIELD",
14
- "validate_confidence_score",
15
- )
10
+ __all__ = ("Reason",)
16
11
 
17
12
 
18
13
  class Reason(BaseModel):
@@ -27,10 +22,9 @@ class Reason(BaseModel):
27
22
  "how well you've met user expectations. Use this guide:\n"
28
23
  " • 1.0: Highly confident\n"
29
24
  " • 0.8-1.0: Reasonably sure\n"
30
- " • 0.5-0.8: Re-check or refine\n"
31
- " • 0.0-0.5: Off track"
25
+ " • 0.5-0.8: Re-check, refine or backtrack\n"
26
+ " • 0.0-0.5: Off track, stop"
32
27
  ),
33
- examples=[0.821, 0.257, 0.923, 0.439],
34
28
  )
35
29
 
36
30
  @field_validator("confidence_score", mode="before")
@@ -51,15 +45,6 @@ def validate_confidence_score(cls, v):
51
45
  return -1
52
46
 
53
47
 
54
- CONFIDENCE_SCORE_FIELD = FieldModel(
55
- name="confidence_score",
56
- annotation=float | None,
57
- default=None,
58
- validator=validate_confidence_score,
59
- validator_kwargs={"mode": "before"},
60
- )
61
-
62
-
63
48
  REASON_FIELD = FieldModel(
64
49
  name="reason",
65
50
  annotation=Reason | None,
@@ -67,4 +52,4 @@ REASON_FIELD = FieldModel(
67
52
  description="**Provide a concise reason for the decision made.**",
68
53
  )
69
54
 
70
- # File: lionagi/libs/fields/reason.py
55
+ # File: lionagi/fields/reason.py
@@ -2,165 +2,20 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
- import importlib.metadata
6
- import importlib.util
7
- import logging
8
- import subprocess
9
- from typing import Any
10
-
11
- from lionagi.utils import run_package_manager_command
12
-
13
-
14
- def check_import(
15
- package_name: str,
16
- module_name: str | None = None,
17
- import_name: str | None = None,
18
- pip_name: str | None = None,
19
- attempt_install: bool = True,
20
- error_message: str = "",
21
- ):
22
- """
23
- Check if a package is installed, attempt to install if not.
24
-
25
- Args:
26
- package_name: The name of the package to check.
27
- module_name: The specific module to import (if any).
28
- import_name: The specific name to import from the module (if any).
29
- pip_name: The name to use for pip installation (if different).
30
- attempt_install: Whether to attempt installation if not found.
31
- error_message: Custom error message to use if package not found.
32
-
33
- Raises:
34
- ImportError: If the package is not found and not installed.
35
- ValueError: If the import fails after installation attempt.
36
- """
37
- if not is_import_installed(package_name):
38
- if attempt_install:
39
- logging.info(
40
- f"Package {package_name} not found. Attempting " "to install.",
41
- )
42
- try:
43
- return install_import(
44
- package_name=package_name,
45
- module_name=module_name,
46
- import_name=import_name,
47
- pip_name=pip_name,
48
- )
49
- except ImportError as e:
50
- raise ValueError(
51
- f"Failed to install {package_name}: {e}"
52
- ) from e
53
- else:
54
- logging.info(
55
- f"Package {package_name} not found. {error_message}",
56
- )
57
- raise ImportError(
58
- f"Package {package_name} not found. {error_message}",
59
- )
60
-
61
- return import_module(
62
- package_name=package_name,
63
- module_name=module_name,
64
- import_name=import_name,
65
- )
66
-
67
-
68
- def import_module(
69
- package_name: str,
70
- module_name: str = None,
71
- import_name: str | list = None,
72
- ) -> Any:
73
- """
74
- Import a module by its path.
75
-
76
- Args:
77
- module_path: The path of the module to import.
78
-
79
- Returns:
80
- The imported module.
81
-
82
- Raises:
83
- ImportError: If the module cannot be imported.
84
- """
85
- try:
86
- full_import_path = (
87
- f"{package_name}.{module_name}" if module_name else package_name
88
- )
89
-
90
- if import_name:
91
- import_name = (
92
- [import_name]
93
- if not isinstance(import_name, list)
94
- else import_name
95
- )
96
- a = __import__(
97
- full_import_path,
98
- fromlist=import_name,
99
- )
100
- if len(import_name) == 1:
101
- return getattr(a, import_name[0])
102
- return [getattr(a, name) for name in import_name]
103
- else:
104
- return __import__(full_import_path)
105
-
106
- except ImportError as e:
107
- raise ImportError(
108
- f"Failed to import module {full_import_path}: {e}"
109
- ) from e
110
-
111
-
112
- def install_import(
113
- package_name: str,
114
- module_name: str | None = None,
115
- import_name: str | None = None,
116
- pip_name: str | None = None,
117
- ):
118
- """
119
- Attempt to import a package, installing it if not found.
120
-
121
- Args:
122
- package_name: The name of the package to import.
123
- module_name: The specific module to import (if any).
124
- import_name: The specific name to import from the module (if any).
125
- pip_name: The name to use for pip installation (if different).
126
-
127
- Raises:
128
- ImportError: If the package cannot be imported or installed.
129
- subprocess.CalledProcessError: If pip installation fails.
130
- """
131
- pip_name = pip_name or package_name
132
-
133
- try:
134
- return import_module(
135
- package_name=package_name,
136
- module_name=module_name,
137
- import_name=import_name,
138
- )
139
- except ImportError:
140
- logging.info(f"Installing {pip_name}...")
141
- try:
142
- run_package_manager_command(["install", pip_name])
143
- return import_module(
144
- package_name=package_name,
145
- module_name=module_name,
146
- import_name=import_name,
147
- )
148
- except subprocess.CalledProcessError as e:
149
- raise ImportError(f"Failed to install {pip_name}: {e}") from e
150
- except ImportError as e:
151
- raise ImportError(
152
- f"Failed to import {pip_name} after installation: {e}"
153
- ) from e
154
-
155
-
156
- def is_import_installed(package_name: str) -> bool:
157
- """
158
- Check if a package is installed.
159
-
160
- Args:
161
- package_name: The name of the package to check.
162
-
163
- Returns:
164
- bool: True if the package is installed, False otherwise.
165
- """
166
- return importlib.util.find_spec(package_name) is not None
5
+ from lionagi.utils import (
6
+ check_import,
7
+ import_module,
8
+ install_import,
9
+ is_import_installed,
10
+ run_package_manager_command,
11
+ )
12
+
13
+ # backward compatibility
14
+
15
+ __all__ = (
16
+ "run_package_manager_command",
17
+ "check_import",
18
+ "import_module",
19
+ "install_import",
20
+ "is_import_installed",
21
+ )
@@ -31,7 +31,7 @@ class SynthlangFramework(Resource):
31
31
  import json
32
32
 
33
33
  fp = here / FRAMEWORK_PATH / "framework_options.json"
34
- with open(fp, "r", encoding="utf-8") as f:
34
+ with open(fp, encoding="utf-8") as f:
35
35
  return json.load(f)
36
36
 
37
37
  @classmethod
@@ -58,4 +58,4 @@ False = "⊭"
58
58
  "⧦⧦⧦" = "⧦"
59
59
  " " = "◻︎"
60
60
  "◻︎◻︎" = "◼︎"
61
- "###" = "#"
61
+ "###" = "#"
@@ -38,4 +38,4 @@ False = "⊭"
38
38
  "⧦⧦⧦" = "⧦"
39
39
  " " = "◻︎"
40
40
  "◻︎◻︎" = "◼︎"
41
- "###" = "#"
41
+ "###" = "#"
@@ -57,4 +57,4 @@ self = "自"
57
57
  Clone = "隆"
58
58
  clone = "隆"
59
59
  derive = "衍"
60
- "println!" = "印"
60
+ "println!" = "印"
@@ -8,7 +8,7 @@ from typing import TYPE_CHECKING, Any, Literal
8
8
 
9
9
  from pydantic import BaseModel
10
10
 
11
- from lionagi.libs.fields.instruct import Instruct
11
+ from lionagi.fields.instruct import Instruct
12
12
  from lionagi.libs.schema.as_readable import as_readable
13
13
  from lionagi.libs.validate.common_field_validators import (
14
14
  validate_model_to_type,