langroid 0.32.2__py3-none-any.whl → 0.33.4__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.
- {langroid-0.32.2.dist-info → langroid-0.33.4.dist-info}/METADATA +149 -123
- langroid-0.33.4.dist-info/RECORD +7 -0
- {langroid-0.32.2.dist-info → langroid-0.33.4.dist-info}/WHEEL +1 -1
- langroid-0.33.4.dist-info/entry_points.txt +4 -0
- pyproject.toml +317 -212
- langroid/__init__.py +0 -106
- langroid/agent/__init__.py +0 -41
- langroid/agent/base.py +0 -1983
- langroid/agent/batch.py +0 -398
- langroid/agent/callbacks/__init__.py +0 -0
- langroid/agent/callbacks/chainlit.py +0 -598
- langroid/agent/chat_agent.py +0 -1899
- langroid/agent/chat_document.py +0 -454
- langroid/agent/openai_assistant.py +0 -882
- langroid/agent/special/__init__.py +0 -59
- langroid/agent/special/arangodb/__init__.py +0 -0
- langroid/agent/special/arangodb/arangodb_agent.py +0 -656
- langroid/agent/special/arangodb/system_messages.py +0 -186
- langroid/agent/special/arangodb/tools.py +0 -107
- langroid/agent/special/arangodb/utils.py +0 -36
- langroid/agent/special/doc_chat_agent.py +0 -1466
- langroid/agent/special/lance_doc_chat_agent.py +0 -262
- langroid/agent/special/lance_rag/__init__.py +0 -9
- langroid/agent/special/lance_rag/critic_agent.py +0 -198
- langroid/agent/special/lance_rag/lance_rag_task.py +0 -82
- langroid/agent/special/lance_rag/query_planner_agent.py +0 -260
- langroid/agent/special/lance_tools.py +0 -61
- langroid/agent/special/neo4j/__init__.py +0 -0
- langroid/agent/special/neo4j/csv_kg_chat.py +0 -174
- langroid/agent/special/neo4j/neo4j_chat_agent.py +0 -433
- langroid/agent/special/neo4j/system_messages.py +0 -120
- langroid/agent/special/neo4j/tools.py +0 -32
- langroid/agent/special/relevance_extractor_agent.py +0 -127
- langroid/agent/special/retriever_agent.py +0 -56
- langroid/agent/special/sql/__init__.py +0 -17
- langroid/agent/special/sql/sql_chat_agent.py +0 -654
- langroid/agent/special/sql/utils/__init__.py +0 -21
- langroid/agent/special/sql/utils/description_extractors.py +0 -190
- langroid/agent/special/sql/utils/populate_metadata.py +0 -85
- langroid/agent/special/sql/utils/system_message.py +0 -35
- langroid/agent/special/sql/utils/tools.py +0 -64
- langroid/agent/special/table_chat_agent.py +0 -263
- langroid/agent/task.py +0 -2095
- langroid/agent/tool_message.py +0 -393
- langroid/agent/tools/__init__.py +0 -38
- langroid/agent/tools/duckduckgo_search_tool.py +0 -50
- langroid/agent/tools/file_tools.py +0 -234
- langroid/agent/tools/google_search_tool.py +0 -39
- langroid/agent/tools/metaphor_search_tool.py +0 -67
- langroid/agent/tools/orchestration.py +0 -303
- langroid/agent/tools/recipient_tool.py +0 -235
- langroid/agent/tools/retrieval_tool.py +0 -32
- langroid/agent/tools/rewind_tool.py +0 -137
- langroid/agent/tools/segment_extract_tool.py +0 -41
- langroid/agent/xml_tool_message.py +0 -382
- langroid/cachedb/__init__.py +0 -17
- langroid/cachedb/base.py +0 -58
- langroid/cachedb/momento_cachedb.py +0 -108
- langroid/cachedb/redis_cachedb.py +0 -153
- langroid/embedding_models/__init__.py +0 -39
- langroid/embedding_models/base.py +0 -74
- langroid/embedding_models/models.py +0 -461
- langroid/embedding_models/protoc/__init__.py +0 -0
- langroid/embedding_models/protoc/embeddings.proto +0 -19
- langroid/embedding_models/protoc/embeddings_pb2.py +0 -33
- langroid/embedding_models/protoc/embeddings_pb2.pyi +0 -50
- langroid/embedding_models/protoc/embeddings_pb2_grpc.py +0 -79
- langroid/embedding_models/remote_embeds.py +0 -153
- langroid/exceptions.py +0 -65
- langroid/language_models/__init__.py +0 -53
- langroid/language_models/azure_openai.py +0 -153
- langroid/language_models/base.py +0 -678
- langroid/language_models/config.py +0 -18
- langroid/language_models/mock_lm.py +0 -124
- langroid/language_models/openai_gpt.py +0 -1964
- langroid/language_models/prompt_formatter/__init__.py +0 -16
- langroid/language_models/prompt_formatter/base.py +0 -40
- langroid/language_models/prompt_formatter/hf_formatter.py +0 -132
- langroid/language_models/prompt_formatter/llama2_formatter.py +0 -75
- langroid/language_models/utils.py +0 -151
- langroid/mytypes.py +0 -84
- langroid/parsing/__init__.py +0 -52
- langroid/parsing/agent_chats.py +0 -38
- langroid/parsing/code_parser.py +0 -121
- langroid/parsing/document_parser.py +0 -718
- langroid/parsing/para_sentence_split.py +0 -62
- langroid/parsing/parse_json.py +0 -155
- langroid/parsing/parser.py +0 -313
- langroid/parsing/repo_loader.py +0 -790
- langroid/parsing/routing.py +0 -36
- langroid/parsing/search.py +0 -275
- langroid/parsing/spider.py +0 -102
- langroid/parsing/table_loader.py +0 -94
- langroid/parsing/url_loader.py +0 -111
- langroid/parsing/urls.py +0 -273
- langroid/parsing/utils.py +0 -373
- langroid/parsing/web_search.py +0 -155
- langroid/prompts/__init__.py +0 -9
- langroid/prompts/dialog.py +0 -17
- langroid/prompts/prompts_config.py +0 -5
- langroid/prompts/templates.py +0 -141
- langroid/pydantic_v1/__init__.py +0 -10
- langroid/pydantic_v1/main.py +0 -4
- langroid/utils/__init__.py +0 -19
- langroid/utils/algorithms/__init__.py +0 -3
- langroid/utils/algorithms/graph.py +0 -103
- langroid/utils/configuration.py +0 -98
- langroid/utils/constants.py +0 -30
- langroid/utils/git_utils.py +0 -252
- langroid/utils/globals.py +0 -49
- langroid/utils/logging.py +0 -135
- langroid/utils/object_registry.py +0 -66
- langroid/utils/output/__init__.py +0 -20
- langroid/utils/output/citations.py +0 -41
- langroid/utils/output/printing.py +0 -99
- langroid/utils/output/status.py +0 -40
- langroid/utils/pandas_utils.py +0 -30
- langroid/utils/pydantic_utils.py +0 -602
- langroid/utils/system.py +0 -286
- langroid/utils/types.py +0 -93
- langroid/vector_store/__init__.py +0 -50
- langroid/vector_store/base.py +0 -357
- langroid/vector_store/chromadb.py +0 -214
- langroid/vector_store/lancedb.py +0 -401
- langroid/vector_store/meilisearch.py +0 -299
- langroid/vector_store/momento.py +0 -278
- langroid/vector_store/qdrantdb.py +0 -468
- langroid-0.32.2.dist-info/RECORD +0 -128
- {langroid-0.32.2.dist-info → langroid-0.33.4.dist-info/licenses}/LICENSE +0 -0
langroid/utils/git_utils.py
DELETED
@@ -1,252 +0,0 @@
|
|
1
|
-
import fnmatch
|
2
|
-
import logging
|
3
|
-
import textwrap
|
4
|
-
from pathlib import Path
|
5
|
-
from typing import List
|
6
|
-
|
7
|
-
import git
|
8
|
-
from github import Github, GithubException
|
9
|
-
|
10
|
-
from langroid.utils.system import create_file
|
11
|
-
|
12
|
-
logger = logging.getLogger(__name__)
|
13
|
-
|
14
|
-
|
15
|
-
def git_read_file(repo: str, filepath: str) -> str:
|
16
|
-
"""
|
17
|
-
Read the contents of a file from a GitHub repository.
|
18
|
-
|
19
|
-
Args:
|
20
|
-
repo (str): The GitHub repository in the format "owner/repo"
|
21
|
-
filepath (str): The file path relative to the repository root
|
22
|
-
|
23
|
-
Returns:
|
24
|
-
str: The contents of the file as a string
|
25
|
-
"""
|
26
|
-
try:
|
27
|
-
g = Github()
|
28
|
-
github_repo = g.get_repo(repo)
|
29
|
-
file_content = github_repo.get_contents(filepath)
|
30
|
-
if isinstance(file_content, list) and len(file_content) > 0:
|
31
|
-
return file_content[0].decoded_content.decode("utf-8")
|
32
|
-
elif hasattr(file_content, "decoded_content"):
|
33
|
-
return file_content.decoded_content.decode("utf-8")
|
34
|
-
else:
|
35
|
-
logger.error(f"Unexpected file_content type: {type(file_content)}")
|
36
|
-
return ""
|
37
|
-
except GithubException as e:
|
38
|
-
logger.error(f"An error occurred while reading file {filepath}: {e}")
|
39
|
-
return ""
|
40
|
-
|
41
|
-
|
42
|
-
def get_file_list(repo: str, dir: str, pat: str = "") -> List[str]:
|
43
|
-
"""
|
44
|
-
Get a list of files in a specified directory of a GitHub repository.
|
45
|
-
|
46
|
-
Args:
|
47
|
-
repo (str): The GitHub repository in the format "owner/repo"
|
48
|
-
dir (str): The directory path relative to the repository root
|
49
|
-
pat (str): Optional wildcard pattern to filter file names (default: "")
|
50
|
-
|
51
|
-
Returns:
|
52
|
-
List[str]: A list of file paths in the specified directory
|
53
|
-
"""
|
54
|
-
try:
|
55
|
-
g = Github()
|
56
|
-
github_repo = g.get_repo(repo)
|
57
|
-
contents = github_repo.get_contents(dir)
|
58
|
-
|
59
|
-
file_list = []
|
60
|
-
if isinstance(contents, list):
|
61
|
-
file_list = [content.path for content in contents if content.type == "file"]
|
62
|
-
elif hasattr(contents, "path") and hasattr(contents, "type"):
|
63
|
-
if contents.type == "file":
|
64
|
-
file_list = [contents.path]
|
65
|
-
|
66
|
-
if pat:
|
67
|
-
file_list = [file for file in file_list if fnmatch.fnmatch(file, pat)]
|
68
|
-
return sorted(file_list)
|
69
|
-
|
70
|
-
except GithubException as e:
|
71
|
-
logger.error(f"An error occurred while fetching file list: {e}")
|
72
|
-
return []
|
73
|
-
|
74
|
-
|
75
|
-
def git_init_repo(dir: str) -> git.Repo | None:
|
76
|
-
"""
|
77
|
-
Set up a Git repository in the specified directory.
|
78
|
-
|
79
|
-
Args:
|
80
|
-
dir (str): Path to the directory where the Git repository should be initialized
|
81
|
-
|
82
|
-
Returns:
|
83
|
-
git.Repo: The initialized Git repository object
|
84
|
-
"""
|
85
|
-
repo_path = Path(dir).expanduser()
|
86
|
-
try:
|
87
|
-
repo = git.Repo.init(repo_path)
|
88
|
-
logger.info(f"Git repository initialized in {repo_path}")
|
89
|
-
|
90
|
-
gitignore_content = textwrap.dedent(
|
91
|
-
"""
|
92
|
-
/target/
|
93
|
-
**/*.rs.bk
|
94
|
-
Cargo.lock
|
95
|
-
"""
|
96
|
-
).strip()
|
97
|
-
|
98
|
-
gitignore_path = repo_path / ".gitignore"
|
99
|
-
create_file(gitignore_path, gitignore_content)
|
100
|
-
logger.info(f"Created .gitignore file in {repo_path}")
|
101
|
-
|
102
|
-
# Ensure the default branch is 'main'
|
103
|
-
# Check if we're on the master branch
|
104
|
-
if repo.active_branch.name == "master":
|
105
|
-
# Rename the branch
|
106
|
-
repo.git.branch("-m", "master", "main")
|
107
|
-
print("Branch renamed from 'master' to 'main'")
|
108
|
-
else:
|
109
|
-
print("Current branch is not 'master'. No changes made.")
|
110
|
-
return repo
|
111
|
-
except git.GitCommandError as e:
|
112
|
-
logger.error(f"An error occurred while initializing the repository: {e}")
|
113
|
-
return None
|
114
|
-
|
115
|
-
|
116
|
-
def git_commit_file(repo: git.Repo, filepath: str, msg: str) -> None:
|
117
|
-
"""
|
118
|
-
Commit a file to a Git repository.
|
119
|
-
|
120
|
-
Args:
|
121
|
-
repo (git.Repo): The Git repository object
|
122
|
-
filepath (str): Path to the file to be committed
|
123
|
-
msg (str): The commit message
|
124
|
-
|
125
|
-
Returns:
|
126
|
-
None
|
127
|
-
"""
|
128
|
-
try:
|
129
|
-
repo.index.add([filepath])
|
130
|
-
commit_msg = msg or f"Updated {filepath}"
|
131
|
-
repo.index.commit(commit_msg)
|
132
|
-
logger.info(f"Successfully committed {filepath}: {commit_msg}")
|
133
|
-
except git.GitCommandError as e:
|
134
|
-
logger.error(f"An error occurred while committing: {e}")
|
135
|
-
|
136
|
-
|
137
|
-
def git_commit_mods(repo: git.Repo, msg: str = "commit all changes") -> None:
|
138
|
-
"""
|
139
|
-
Commit all modifications in the Git repository.
|
140
|
-
Does not raise an error if there's nothing to commit.
|
141
|
-
|
142
|
-
Args:
|
143
|
-
repo (git.Repo): The Git repository object
|
144
|
-
|
145
|
-
Returns:
|
146
|
-
None
|
147
|
-
"""
|
148
|
-
try:
|
149
|
-
if repo.is_dirty():
|
150
|
-
repo.git.add(update=True)
|
151
|
-
repo.index.commit(msg)
|
152
|
-
logger.info("Successfully committed all modifications")
|
153
|
-
else:
|
154
|
-
logger.info("No changes to commit")
|
155
|
-
except git.GitCommandError as e:
|
156
|
-
logger.error(f"An error occurred while committing modifications: {e}")
|
157
|
-
|
158
|
-
|
159
|
-
def git_restore_repo(repo: git.Repo) -> None:
|
160
|
-
"""
|
161
|
-
Restore all unstaged, uncommitted changes in the Git repository.
|
162
|
-
This function undoes any dirty files to the last commit.
|
163
|
-
|
164
|
-
Args:
|
165
|
-
repo (git.Repo): The Git repository object
|
166
|
-
|
167
|
-
Returns:
|
168
|
-
None
|
169
|
-
"""
|
170
|
-
try:
|
171
|
-
if repo.is_dirty():
|
172
|
-
repo.git.restore(".")
|
173
|
-
logger.info("Successfully restored all unstaged changes")
|
174
|
-
else:
|
175
|
-
logger.info("No unstaged changes to restore")
|
176
|
-
except git.GitCommandError as e:
|
177
|
-
logger.error(f"An error occurred while restoring changes: {e}")
|
178
|
-
|
179
|
-
|
180
|
-
def git_restore_file(repo: git.Repo, file_path: str) -> None:
|
181
|
-
"""
|
182
|
-
Restore a specific file in the Git repository to its state in the last commit.
|
183
|
-
This function undoes changes to the specified file.
|
184
|
-
|
185
|
-
Args:
|
186
|
-
repo (git.Repo): The Git repository object
|
187
|
-
file_path (str): Path to the file to be restored
|
188
|
-
|
189
|
-
Returns:
|
190
|
-
None
|
191
|
-
"""
|
192
|
-
try:
|
193
|
-
repo.git.restore(file_path)
|
194
|
-
logger.info(f"Successfully restored file: {file_path}")
|
195
|
-
except git.GitCommandError as e:
|
196
|
-
logger.error(f"An error occurred while restoring file {file_path}: {e}")
|
197
|
-
|
198
|
-
|
199
|
-
def git_create_checkout_branch(repo: git.Repo, branch: str) -> None:
|
200
|
-
"""
|
201
|
-
Create and checkout a new branch in the given Git repository.
|
202
|
-
If the branch already exists, it will be checked out.
|
203
|
-
If we're already on the specified branch, no action is taken.
|
204
|
-
|
205
|
-
Args:
|
206
|
-
repo (git.Repo): The Git repository object
|
207
|
-
branch (str): The name of the branch to create or checkout
|
208
|
-
|
209
|
-
Returns:
|
210
|
-
None
|
211
|
-
"""
|
212
|
-
try:
|
213
|
-
if repo.active_branch.name == branch:
|
214
|
-
logger.info(f"Already on branch: {branch}")
|
215
|
-
return
|
216
|
-
|
217
|
-
if branch in repo.heads:
|
218
|
-
repo.heads[branch].checkout()
|
219
|
-
logger.info(f"Checked out existing branch: {branch}")
|
220
|
-
else:
|
221
|
-
new_branch = repo.create_head(branch)
|
222
|
-
new_branch.checkout()
|
223
|
-
logger.info(f"Created and checked out new branch: {branch}")
|
224
|
-
except git.GitCommandError as e:
|
225
|
-
logger.error(f"An error occurred while creating/checking out branch: {e}")
|
226
|
-
|
227
|
-
|
228
|
-
def git_diff_file(repo: git.Repo, filepath: str) -> str:
|
229
|
-
"""
|
230
|
-
Show diffs of file between the latest commit and the previous one if any.
|
231
|
-
|
232
|
-
Args:
|
233
|
-
repo (git.Repo): The Git repository object
|
234
|
-
filepath (str): Path to the file to be diffed
|
235
|
-
|
236
|
-
Returns:
|
237
|
-
str: The diff output as a string
|
238
|
-
"""
|
239
|
-
try:
|
240
|
-
# Get the two most recent commits
|
241
|
-
commits = list(repo.iter_commits(paths=filepath, max_count=2))
|
242
|
-
|
243
|
-
if len(commits) < 2:
|
244
|
-
return "No previous commit found for comparison."
|
245
|
-
|
246
|
-
# Get the diff between the two commits for the specific file
|
247
|
-
diff = repo.git.diff(commits[1].hexsha, commits[0].hexsha, filepath)
|
248
|
-
|
249
|
-
return str(diff)
|
250
|
-
except git.GitCommandError as e:
|
251
|
-
logger.error(f"An error occurred while getting diff: {e}")
|
252
|
-
return f"Error: {str(e)}"
|
langroid/utils/globals.py
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
from typing import Any, Dict, Optional, Type, TypeVar
|
2
|
-
|
3
|
-
from langroid.pydantic_v1 import BaseModel
|
4
|
-
|
5
|
-
T = TypeVar("T", bound="GlobalState")
|
6
|
-
|
7
|
-
|
8
|
-
class GlobalState(BaseModel):
|
9
|
-
"""A base Pydantic model for global states."""
|
10
|
-
|
11
|
-
_instance: Optional["GlobalState"] = None
|
12
|
-
|
13
|
-
@classmethod
|
14
|
-
def get_instance(cls: Type["GlobalState"]) -> "GlobalState":
|
15
|
-
"""
|
16
|
-
Get the global instance of the specific subclass.
|
17
|
-
|
18
|
-
Returns:
|
19
|
-
The global instance of the subclass.
|
20
|
-
"""
|
21
|
-
if cls._instance is None:
|
22
|
-
cls._instance = cls()
|
23
|
-
return cls._instance
|
24
|
-
|
25
|
-
@classmethod
|
26
|
-
def set_values(cls: Type[T], **kwargs: Dict[str, Any]) -> None:
|
27
|
-
"""
|
28
|
-
Set values on the global instance of the specific subclass.
|
29
|
-
|
30
|
-
Args:
|
31
|
-
**kwargs: The fields and their values to set.
|
32
|
-
"""
|
33
|
-
instance = cls.get_instance()
|
34
|
-
for key, value in kwargs.items():
|
35
|
-
setattr(instance, key, value)
|
36
|
-
|
37
|
-
@classmethod
|
38
|
-
def get_value(cls: Type[T], name: str) -> Any:
|
39
|
-
"""
|
40
|
-
Retrieve the value of a specific field from the global instance.
|
41
|
-
|
42
|
-
Args:
|
43
|
-
name (str): The name of the field to retrieve.
|
44
|
-
|
45
|
-
Returns:
|
46
|
-
str: The value of the specified field.
|
47
|
-
"""
|
48
|
-
instance = cls.get_instance()
|
49
|
-
return getattr(instance, name)
|
langroid/utils/logging.py
DELETED
@@ -1,135 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
import os.path
|
3
|
-
from typing import no_type_check
|
4
|
-
|
5
|
-
import colorlog
|
6
|
-
from rich.console import Console
|
7
|
-
from rich.markup import escape
|
8
|
-
|
9
|
-
|
10
|
-
# Define a function to set up the colored logger
|
11
|
-
def setup_colored_logging() -> None:
|
12
|
-
# Define the log format with color codes
|
13
|
-
log_format = "%(log_color)s%(asctime)s - %(levelname)s - %(message)s%(reset)s"
|
14
|
-
# Create a color formatter
|
15
|
-
color_formatter = colorlog.ColoredFormatter(
|
16
|
-
log_format,
|
17
|
-
datefmt="%Y-%m-%d %H:%M:%S",
|
18
|
-
reset=True,
|
19
|
-
log_colors={
|
20
|
-
"DEBUG": "cyan",
|
21
|
-
"INFO": "green",
|
22
|
-
"WARNING": "yellow",
|
23
|
-
"ERROR": "red",
|
24
|
-
"CRITICAL": "red,bg_white",
|
25
|
-
},
|
26
|
-
)
|
27
|
-
# Configure the root logger to use the color formatter
|
28
|
-
handler = logging.StreamHandler()
|
29
|
-
handler.setFormatter(color_formatter)
|
30
|
-
logger = logging.getLogger()
|
31
|
-
logger.addHandler(handler)
|
32
|
-
# logger.setLevel(logging.DEBUG)
|
33
|
-
|
34
|
-
|
35
|
-
def setup_logger(
|
36
|
-
name: str,
|
37
|
-
level: int = logging.INFO,
|
38
|
-
terminal: bool = False,
|
39
|
-
) -> logging.Logger:
|
40
|
-
"""
|
41
|
-
Set up a logger of module `name` at a desired level.
|
42
|
-
Args:
|
43
|
-
name: module name
|
44
|
-
level: desired logging level
|
45
|
-
Returns:
|
46
|
-
logger
|
47
|
-
"""
|
48
|
-
logger = logging.getLogger(name)
|
49
|
-
logger.setLevel(level)
|
50
|
-
if not logger.hasHandlers() and terminal:
|
51
|
-
handler = logging.StreamHandler()
|
52
|
-
formatter = logging.Formatter(
|
53
|
-
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
54
|
-
)
|
55
|
-
handler.setFormatter(formatter)
|
56
|
-
logger.addHandler(handler)
|
57
|
-
return logger
|
58
|
-
|
59
|
-
|
60
|
-
def setup_console_logger(name: str) -> logging.Logger:
|
61
|
-
logger = setup_logger(name)
|
62
|
-
handler = logging.StreamHandler()
|
63
|
-
handler.setLevel(logging.INFO)
|
64
|
-
formatter = logging.Formatter(
|
65
|
-
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
66
|
-
)
|
67
|
-
handler.setFormatter(formatter)
|
68
|
-
logger.addHandler(handler)
|
69
|
-
return logger
|
70
|
-
|
71
|
-
|
72
|
-
def setup_file_logger(
|
73
|
-
name: str,
|
74
|
-
filename: str,
|
75
|
-
append: bool = False,
|
76
|
-
log_format: bool = False,
|
77
|
-
propagate: bool = False,
|
78
|
-
) -> logging.Logger:
|
79
|
-
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
80
|
-
file_mode = "a" if append else "w"
|
81
|
-
logger = setup_logger(name, terminal=False)
|
82
|
-
handler = logging.FileHandler(filename, mode=file_mode)
|
83
|
-
handler.setLevel(logging.INFO)
|
84
|
-
if log_format:
|
85
|
-
formatter = logging.Formatter(
|
86
|
-
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
87
|
-
)
|
88
|
-
else:
|
89
|
-
formatter = logging.Formatter("%(message)s")
|
90
|
-
handler.setFormatter(formatter)
|
91
|
-
logger.addHandler(handler)
|
92
|
-
logger.propagate = propagate
|
93
|
-
return logger
|
94
|
-
|
95
|
-
|
96
|
-
def setup_loggers_for_package(package_name: str, level: int) -> None:
|
97
|
-
"""
|
98
|
-
Set up loggers for all modules in a package.
|
99
|
-
This ensures that log-levels of modules outside the package are not affected.
|
100
|
-
Args:
|
101
|
-
package_name: main package name
|
102
|
-
level: desired logging level
|
103
|
-
Returns:
|
104
|
-
"""
|
105
|
-
import importlib
|
106
|
-
import pkgutil
|
107
|
-
|
108
|
-
package = importlib.import_module(package_name)
|
109
|
-
for _, module_name, _ in pkgutil.walk_packages(
|
110
|
-
package.__path__, package.__name__ + "."
|
111
|
-
):
|
112
|
-
module = importlib.import_module(module_name)
|
113
|
-
setup_logger(module.__name__, level)
|
114
|
-
|
115
|
-
|
116
|
-
class RichFileLogger:
|
117
|
-
def __init__(self, log_file: str, append: bool = False, color: bool = True):
|
118
|
-
os.makedirs(os.path.dirname(log_file), exist_ok=True)
|
119
|
-
self.log_file = log_file
|
120
|
-
if not append:
|
121
|
-
if os.path.exists(self.log_file):
|
122
|
-
os.remove(self.log_file)
|
123
|
-
self.file = None
|
124
|
-
self.console = None
|
125
|
-
self.append = append
|
126
|
-
self.color = color
|
127
|
-
|
128
|
-
@no_type_check
|
129
|
-
def log(self, message: str) -> None:
|
130
|
-
with open(self.log_file, "a") as f:
|
131
|
-
if self.color:
|
132
|
-
console = Console(file=f, force_terminal=True, width=200)
|
133
|
-
console.print(escape(message))
|
134
|
-
else:
|
135
|
-
print(message, file=f)
|
@@ -1,66 +0,0 @@
|
|
1
|
-
import time
|
2
|
-
from typing import TYPE_CHECKING, Dict, Optional, TypeAlias, TypeVar
|
3
|
-
from uuid import uuid4
|
4
|
-
|
5
|
-
from langroid.pydantic_v1 import BaseModel
|
6
|
-
|
7
|
-
if TYPE_CHECKING:
|
8
|
-
from langroid.agent.base import Agent
|
9
|
-
from langroid.agent.chat_agent import ChatAgent
|
10
|
-
from langroid.agent.chat_document import ChatDocument
|
11
|
-
|
12
|
-
# any derivative of BaseModel that has an id() method or an id attribute
|
13
|
-
ObjWithId: TypeAlias = ChatDocument | ChatAgent | Agent
|
14
|
-
else:
|
15
|
-
ObjWithId = BaseModel
|
16
|
-
|
17
|
-
# Define a type variable that can be any subclass of BaseModel
|
18
|
-
T = TypeVar("T", bound=BaseModel)
|
19
|
-
|
20
|
-
|
21
|
-
class ObjectRegistry:
|
22
|
-
"""A global registry to hold id -> object mappings."""
|
23
|
-
|
24
|
-
registry: Dict[str, ObjWithId] = {}
|
25
|
-
|
26
|
-
@classmethod
|
27
|
-
def add(cls, obj: ObjWithId) -> str:
|
28
|
-
"""Adds an object to the registry, returning the object's ID."""
|
29
|
-
object_id = obj.id() if callable(obj.id) else obj.id
|
30
|
-
cls.registry[object_id] = obj
|
31
|
-
return object_id
|
32
|
-
|
33
|
-
@classmethod
|
34
|
-
def get(cls, obj_id: str) -> Optional[ObjWithId]:
|
35
|
-
"""Retrieves an object by ID if it still exists."""
|
36
|
-
return cls.registry.get(obj_id)
|
37
|
-
|
38
|
-
@classmethod
|
39
|
-
def register_object(cls, obj: ObjWithId) -> str:
|
40
|
-
"""Registers an object in the registry, returning the object's ID."""
|
41
|
-
return cls.add(obj)
|
42
|
-
|
43
|
-
@classmethod
|
44
|
-
def remove(cls, obj_id: str) -> None:
|
45
|
-
"""Removes an object from the registry."""
|
46
|
-
if obj_id in cls.registry:
|
47
|
-
del cls.registry[obj_id]
|
48
|
-
|
49
|
-
@classmethod
|
50
|
-
def cleanup(cls) -> None:
|
51
|
-
"""Cleans up the registry by removing entries where the object is None."""
|
52
|
-
to_remove = [key for key, value in cls.registry.items() if value is None]
|
53
|
-
for key in to_remove:
|
54
|
-
del cls.registry[key]
|
55
|
-
|
56
|
-
@staticmethod
|
57
|
-
def new_id() -> str:
|
58
|
-
"""Generates a new unique ID."""
|
59
|
-
return str(uuid4())
|
60
|
-
|
61
|
-
|
62
|
-
def scheduled_cleanup(interval: int = 600) -> None:
|
63
|
-
"""Periodically cleans up the global registry every 'interval' seconds."""
|
64
|
-
while True:
|
65
|
-
ObjectRegistry.cleanup()
|
66
|
-
time.sleep(interval)
|
@@ -1,20 +0,0 @@
|
|
1
|
-
from . import printing
|
2
|
-
from .printing import (
|
3
|
-
shorten_text,
|
4
|
-
print_long_text,
|
5
|
-
show_if_debug,
|
6
|
-
SuppressLoggerWarnings,
|
7
|
-
PrintColored,
|
8
|
-
)
|
9
|
-
from .status import status
|
10
|
-
|
11
|
-
|
12
|
-
__all__ = [
|
13
|
-
"printing",
|
14
|
-
"shorten_text",
|
15
|
-
"print_long_text",
|
16
|
-
"show_if_debug",
|
17
|
-
"SuppressLoggerWarnings",
|
18
|
-
"PrintColored",
|
19
|
-
"status",
|
20
|
-
]
|
@@ -1,41 +0,0 @@
|
|
1
|
-
def extract_markdown_references(md_string: str) -> list[int]:
|
2
|
-
"""
|
3
|
-
Extracts markdown references (e.g., [^1], [^2]) from a string and returns
|
4
|
-
them as a sorted list of integers.
|
5
|
-
|
6
|
-
Args:
|
7
|
-
md_string (str): The markdown string containing references.
|
8
|
-
|
9
|
-
Returns:
|
10
|
-
list[int]: A sorted list of unique integers from the markdown references.
|
11
|
-
"""
|
12
|
-
import re
|
13
|
-
|
14
|
-
# Regex to find all occurrences of [^<number>]
|
15
|
-
matches = re.findall(r"\[\^(\d+)\]", md_string)
|
16
|
-
# Convert matches to integers, remove duplicates with set, and sort
|
17
|
-
return sorted(set(int(match) for match in matches))
|
18
|
-
|
19
|
-
|
20
|
-
def format_footnote_text(content: str, width: int = 80) -> str:
|
21
|
-
"""
|
22
|
-
Formats the content part of a footnote (i.e. not the first line that
|
23
|
-
appears right after the reference [^4])
|
24
|
-
It wraps the text so that no line is longer than the specified width and indents
|
25
|
-
lines as necessary for markdown footnotes.
|
26
|
-
|
27
|
-
Args:
|
28
|
-
content (str): The text of the footnote to be formatted.
|
29
|
-
width (int): Maximum width of the text lines.
|
30
|
-
|
31
|
-
Returns:
|
32
|
-
str: Properly formatted markdown footnote text.
|
33
|
-
"""
|
34
|
-
import textwrap
|
35
|
-
|
36
|
-
# Wrap the text to the specified width
|
37
|
-
wrapped_lines = textwrap.wrap(content, width)
|
38
|
-
if len(wrapped_lines) == 0:
|
39
|
-
return ""
|
40
|
-
indent = " " # Indentation for markdown footnotes
|
41
|
-
return indent + ("\n" + indent).join(wrapped_lines)
|
@@ -1,99 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
import sys
|
3
|
-
from contextlib import contextmanager
|
4
|
-
from typing import Any, Iterator, Optional, Type
|
5
|
-
|
6
|
-
from rich import print as rprint
|
7
|
-
from rich.text import Text
|
8
|
-
|
9
|
-
from langroid.utils.configuration import settings
|
10
|
-
from langroid.utils.constants import Colors
|
11
|
-
|
12
|
-
|
13
|
-
def shorten_text(text: str, chars: int = 40) -> str:
|
14
|
-
text = " ".join(text.split())
|
15
|
-
return text[:chars] + "..." + text[-chars:] if len(text) > 2 * chars else text
|
16
|
-
|
17
|
-
|
18
|
-
def print_long_text(
|
19
|
-
color: str, style: str, preamble: str, text: str, chars: Optional[int] = None
|
20
|
-
) -> None:
|
21
|
-
if chars is not None:
|
22
|
-
text = " ".join(text.split())
|
23
|
-
text = text[:chars] + "..." + text[-chars:] if len(text) > 2 * chars else text
|
24
|
-
styled_text = Text(text, style=style)
|
25
|
-
rprint(f"[{color}]{preamble} {styled_text}")
|
26
|
-
|
27
|
-
|
28
|
-
def show_if_debug(
|
29
|
-
text: str,
|
30
|
-
preamble: str,
|
31
|
-
chars: Optional[int] = None,
|
32
|
-
color: str = "red",
|
33
|
-
style: str = "italic",
|
34
|
-
) -> None:
|
35
|
-
if settings.debug:
|
36
|
-
print_long_text(color, style, preamble, text, chars)
|
37
|
-
|
38
|
-
|
39
|
-
class PrintColored:
|
40
|
-
"""Context to temporarily print in a desired color"""
|
41
|
-
|
42
|
-
def __init__(self, color: str):
|
43
|
-
self.color = color
|
44
|
-
|
45
|
-
def __enter__(self) -> None:
|
46
|
-
sys.stdout.write(self.color)
|
47
|
-
sys.stdout.flush()
|
48
|
-
|
49
|
-
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
50
|
-
print(Colors().RESET)
|
51
|
-
|
52
|
-
|
53
|
-
@contextmanager
|
54
|
-
def silence_stdout() -> Iterator[None]:
|
55
|
-
"""
|
56
|
-
Temporarily silence all output to stdout and from rich.print.
|
57
|
-
|
58
|
-
This context manager redirects all output written to stdout (which includes
|
59
|
-
outputs from the built-in print function and rich.print) to /dev/null on
|
60
|
-
UNIX-like systems or NUL on Windows. Once the context block exits, stdout is
|
61
|
-
restored to its original state.
|
62
|
-
|
63
|
-
Example:
|
64
|
-
with silence_stdout_and_rich():
|
65
|
-
print("This won't be printed")
|
66
|
-
rich.print("This also won't be printed")
|
67
|
-
|
68
|
-
Note:
|
69
|
-
This suppresses both standard print functions and the rich library outputs.
|
70
|
-
"""
|
71
|
-
platform_null = "/dev/null" if sys.platform != "win32" else "NUL"
|
72
|
-
original_stdout = sys.stdout
|
73
|
-
fnull = open(platform_null, "w")
|
74
|
-
sys.stdout = fnull
|
75
|
-
try:
|
76
|
-
yield
|
77
|
-
finally:
|
78
|
-
sys.stdout = original_stdout
|
79
|
-
fnull.close()
|
80
|
-
|
81
|
-
|
82
|
-
class SuppressLoggerWarnings:
|
83
|
-
def __init__(self, logger: str | None = None):
|
84
|
-
# If no logger name is given, get the root logger
|
85
|
-
self.logger = logging.getLogger(logger)
|
86
|
-
self.original_level = self.logger.getEffectiveLevel()
|
87
|
-
|
88
|
-
def __enter__(self) -> None:
|
89
|
-
# Set the logging level to 'ERROR' to suppress warnings
|
90
|
-
self.logger.setLevel(logging.ERROR)
|
91
|
-
|
92
|
-
def __exit__(
|
93
|
-
self,
|
94
|
-
exc_type: Optional[Type[BaseException]],
|
95
|
-
exc_value: Optional[BaseException],
|
96
|
-
traceback: Any,
|
97
|
-
) -> None:
|
98
|
-
# Reset the logging level to its original value
|
99
|
-
self.logger.setLevel(self.original_level)
|
langroid/utils/output/status.py
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
from contextlib import AbstractContextManager, ExitStack
|
3
|
-
from typing import Any
|
4
|
-
|
5
|
-
from rich.console import Console
|
6
|
-
from rich.errors import LiveError
|
7
|
-
|
8
|
-
from langroid.utils.configuration import quiet_mode, settings
|
9
|
-
|
10
|
-
console = Console()
|
11
|
-
logger = logging.getLogger(__name__)
|
12
|
-
logger.setLevel(logging.INFO)
|
13
|
-
|
14
|
-
|
15
|
-
def status(
|
16
|
-
msg: str,
|
17
|
-
log_if_quiet: bool = True,
|
18
|
-
) -> AbstractContextManager[Any]:
|
19
|
-
"""
|
20
|
-
Displays a rich spinner if not in quiet mode, else optionally logs the message.
|
21
|
-
"""
|
22
|
-
stack = ExitStack()
|
23
|
-
logged = False
|
24
|
-
if settings.quiet and log_if_quiet:
|
25
|
-
logged = True
|
26
|
-
logger.info(msg)
|
27
|
-
|
28
|
-
if not settings.quiet:
|
29
|
-
try:
|
30
|
-
stack.enter_context(console.status(msg))
|
31
|
-
except LiveError:
|
32
|
-
if not logged:
|
33
|
-
logger.info(msg)
|
34
|
-
|
35
|
-
# When using rich spinner, we enforce quiet mode
|
36
|
-
# (since output will be messy otherwise);
|
37
|
-
# We make an exception to this when debug is enabled.
|
38
|
-
stack.enter_context(quiet_mode(not settings.debug))
|
39
|
-
|
40
|
-
return stack
|