langroid 0.53.10__tar.gz → 0.53.12__tar.gz

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 (140) hide show
  1. {langroid-0.53.10 → langroid-0.53.12}/PKG-INFO +1 -1
  2. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/task.py +6 -1
  3. {langroid-0.53.10 → langroid-0.53.12}/langroid/embedding_models/models.py +4 -2
  4. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/logging.py +82 -16
  5. {langroid-0.53.10 → langroid-0.53.12}/pyproject.toml +1 -1
  6. {langroid-0.53.10 → langroid-0.53.12}/.gitignore +0 -0
  7. {langroid-0.53.10 → langroid-0.53.12}/LICENSE +0 -0
  8. {langroid-0.53.10 → langroid-0.53.12}/README.md +0 -0
  9. {langroid-0.53.10 → langroid-0.53.12}/langroid/__init__.py +0 -0
  10. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/__init__.py +0 -0
  11. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/base.py +0 -0
  12. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/batch.py +0 -0
  13. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/callbacks/__init__.py +0 -0
  14. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/callbacks/chainlit.py +0 -0
  15. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/chat_agent.py +0 -0
  16. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/chat_document.py +0 -0
  17. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/openai_assistant.py +0 -0
  18. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/__init__.py +0 -0
  19. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/arangodb/__init__.py +0 -0
  20. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/arangodb/arangodb_agent.py +0 -0
  21. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/arangodb/system_messages.py +0 -0
  22. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/arangodb/tools.py +0 -0
  23. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/arangodb/utils.py +0 -0
  24. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/doc_chat_agent.py +0 -0
  25. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/doc_chat_task.py +0 -0
  26. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/lance_doc_chat_agent.py +0 -0
  27. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/lance_rag/__init__.py +0 -0
  28. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/lance_rag/critic_agent.py +0 -0
  29. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/lance_rag/lance_rag_task.py +0 -0
  30. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/lance_rag/query_planner_agent.py +0 -0
  31. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/lance_tools.py +0 -0
  32. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/neo4j/__init__.py +0 -0
  33. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/neo4j/csv_kg_chat.py +0 -0
  34. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/neo4j/neo4j_chat_agent.py +0 -0
  35. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/neo4j/system_messages.py +0 -0
  36. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/neo4j/tools.py +0 -0
  37. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/relevance_extractor_agent.py +0 -0
  38. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/retriever_agent.py +0 -0
  39. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/sql/__init__.py +0 -0
  40. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/sql/sql_chat_agent.py +0 -0
  41. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/sql/utils/__init__.py +0 -0
  42. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/sql/utils/description_extractors.py +0 -0
  43. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/sql/utils/populate_metadata.py +0 -0
  44. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/sql/utils/system_message.py +0 -0
  45. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/sql/utils/tools.py +0 -0
  46. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/special/table_chat_agent.py +0 -0
  47. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tool_message.py +0 -0
  48. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/__init__.py +0 -0
  49. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/duckduckgo_search_tool.py +0 -0
  50. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/exa_search_tool.py +0 -0
  51. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/file_tools.py +0 -0
  52. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/google_search_tool.py +0 -0
  53. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/mcp/__init__.py +0 -0
  54. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/mcp/decorators.py +0 -0
  55. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/mcp/fastmcp_client.py +0 -0
  56. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/metaphor_search_tool.py +0 -0
  57. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/orchestration.py +0 -0
  58. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/recipient_tool.py +0 -0
  59. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/retrieval_tool.py +0 -0
  60. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/rewind_tool.py +0 -0
  61. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/segment_extract_tool.py +0 -0
  62. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/tools/tavily_search_tool.py +0 -0
  63. {langroid-0.53.10 → langroid-0.53.12}/langroid/agent/xml_tool_message.py +0 -0
  64. {langroid-0.53.10 → langroid-0.53.12}/langroid/cachedb/__init__.py +0 -0
  65. {langroid-0.53.10 → langroid-0.53.12}/langroid/cachedb/base.py +0 -0
  66. {langroid-0.53.10 → langroid-0.53.12}/langroid/cachedb/redis_cachedb.py +0 -0
  67. {langroid-0.53.10 → langroid-0.53.12}/langroid/embedding_models/__init__.py +0 -0
  68. {langroid-0.53.10 → langroid-0.53.12}/langroid/embedding_models/base.py +0 -0
  69. {langroid-0.53.10 → langroid-0.53.12}/langroid/embedding_models/protoc/__init__.py +0 -0
  70. {langroid-0.53.10 → langroid-0.53.12}/langroid/embedding_models/protoc/embeddings.proto +0 -0
  71. {langroid-0.53.10 → langroid-0.53.12}/langroid/embedding_models/protoc/embeddings_pb2.py +0 -0
  72. {langroid-0.53.10 → langroid-0.53.12}/langroid/embedding_models/protoc/embeddings_pb2.pyi +0 -0
  73. {langroid-0.53.10 → langroid-0.53.12}/langroid/embedding_models/protoc/embeddings_pb2_grpc.py +0 -0
  74. {langroid-0.53.10 → langroid-0.53.12}/langroid/embedding_models/remote_embeds.py +0 -0
  75. {langroid-0.53.10 → langroid-0.53.12}/langroid/exceptions.py +0 -0
  76. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/__init__.py +0 -0
  77. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/azure_openai.py +0 -0
  78. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/base.py +0 -0
  79. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/config.py +0 -0
  80. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/mcp_client_lm.py +0 -0
  81. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/mock_lm.py +0 -0
  82. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/model_info.py +0 -0
  83. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/openai_gpt.py +0 -0
  84. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/prompt_formatter/__init__.py +0 -0
  85. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/prompt_formatter/base.py +0 -0
  86. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/prompt_formatter/hf_formatter.py +0 -0
  87. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/prompt_formatter/llama2_formatter.py +0 -0
  88. {langroid-0.53.10 → langroid-0.53.12}/langroid/language_models/utils.py +0 -0
  89. {langroid-0.53.10 → langroid-0.53.12}/langroid/mytypes.py +0 -0
  90. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/__init__.py +0 -0
  91. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/agent_chats.py +0 -0
  92. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/code_parser.py +0 -0
  93. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/document_parser.py +0 -0
  94. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/file_attachment.py +0 -0
  95. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/md_parser.py +0 -0
  96. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/para_sentence_split.py +0 -0
  97. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/parse_json.py +0 -0
  98. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/parser.py +0 -0
  99. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/pdf_utils.py +0 -0
  100. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/repo_loader.py +0 -0
  101. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/routing.py +0 -0
  102. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/search.py +0 -0
  103. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/spider.py +0 -0
  104. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/table_loader.py +0 -0
  105. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/url_loader.py +0 -0
  106. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/urls.py +0 -0
  107. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/utils.py +0 -0
  108. {langroid-0.53.10 → langroid-0.53.12}/langroid/parsing/web_search.py +0 -0
  109. {langroid-0.53.10 → langroid-0.53.12}/langroid/prompts/__init__.py +0 -0
  110. {langroid-0.53.10 → langroid-0.53.12}/langroid/prompts/dialog.py +0 -0
  111. {langroid-0.53.10 → langroid-0.53.12}/langroid/prompts/prompts_config.py +0 -0
  112. {langroid-0.53.10 → langroid-0.53.12}/langroid/prompts/templates.py +0 -0
  113. {langroid-0.53.10 → langroid-0.53.12}/langroid/py.typed +0 -0
  114. {langroid-0.53.10 → langroid-0.53.12}/langroid/pydantic_v1/__init__.py +0 -0
  115. {langroid-0.53.10 → langroid-0.53.12}/langroid/pydantic_v1/main.py +0 -0
  116. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/__init__.py +0 -0
  117. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/algorithms/__init__.py +0 -0
  118. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/algorithms/graph.py +0 -0
  119. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/configuration.py +0 -0
  120. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/constants.py +0 -0
  121. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/git_utils.py +0 -0
  122. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/globals.py +0 -0
  123. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/object_registry.py +0 -0
  124. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/output/__init__.py +0 -0
  125. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/output/citations.py +0 -0
  126. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/output/printing.py +0 -0
  127. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/output/status.py +0 -0
  128. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/pandas_utils.py +0 -0
  129. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/pydantic_utils.py +0 -0
  130. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/system.py +0 -0
  131. {langroid-0.53.10 → langroid-0.53.12}/langroid/utils/types.py +0 -0
  132. {langroid-0.53.10 → langroid-0.53.12}/langroid/vector_store/__init__.py +0 -0
  133. {langroid-0.53.10 → langroid-0.53.12}/langroid/vector_store/base.py +0 -0
  134. {langroid-0.53.10 → langroid-0.53.12}/langroid/vector_store/chromadb.py +0 -0
  135. {langroid-0.53.10 → langroid-0.53.12}/langroid/vector_store/lancedb.py +0 -0
  136. {langroid-0.53.10 → langroid-0.53.12}/langroid/vector_store/meilisearch.py +0 -0
  137. {langroid-0.53.10 → langroid-0.53.12}/langroid/vector_store/pineconedb.py +0 -0
  138. {langroid-0.53.10 → langroid-0.53.12}/langroid/vector_store/postgres.py +0 -0
  139. {langroid-0.53.10 → langroid-0.53.12}/langroid/vector_store/qdrantdb.py +0 -0
  140. {langroid-0.53.10 → langroid-0.53.12}/langroid/vector_store/weaviatedb.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langroid
3
- Version: 0.53.10
3
+ Version: 0.53.12
4
4
  Summary: Harness LLMs with Multi-Agent Programming
5
5
  Author-email: Prasad Chalasani <pchalasani@gmail.com>
6
6
  License: MIT
@@ -578,19 +578,24 @@ class Task:
578
578
  return self.pending_message
579
579
 
580
580
  def init_loggers(self) -> None:
581
+ """Initialise per-task Rich and TSV loggers."""
582
+ from langroid.utils.logging import RichFileLogger
583
+
581
584
  if self.caller is not None and self.caller.logger is not None:
582
585
  self.logger = self.caller.logger
583
586
  elif self.logger is None:
584
587
  self.logger = RichFileLogger(
585
588
  str(Path(self.config.logs_dir) / f"{self.name}.log"),
589
+ append=True,
586
590
  color=self.color_log,
587
591
  )
588
592
 
589
593
  if self.caller is not None and self.caller.tsv_logger is not None:
590
594
  self.tsv_logger = self.caller.tsv_logger
591
595
  elif self.tsv_logger is None:
596
+ # unique logger name ensures a distinct `logging.Logger` object
592
597
  self.tsv_logger = setup_file_logger(
593
- "tsv_logger",
598
+ f"tsv_logger.{self.name}.{id(self)}",
594
599
  str(Path(self.config.logs_dir) / f"{self.name}.tsv"),
595
600
  )
596
601
  header = ChatDocLoggerFields().tsv_header()
@@ -521,7 +521,7 @@ class GeminiEmbeddings(EmbeddingModel):
521
521
  for batch in batched(texts, self.config.batch_size):
522
522
  result = self.client.models.embed_content( # type: ignore[attr-defined]
523
523
  model=self.config.model_name,
524
- contents=batch,
524
+ contents=batch, # type: ignore
525
525
  )
526
526
 
527
527
  if not hasattr(result, "embeddings") or not isinstance(
@@ -532,7 +532,9 @@ class GeminiEmbeddings(EmbeddingModel):
532
532
  )
533
533
 
534
534
  # Extract .values from ContentEmbedding objects
535
- all_embeddings.extend([emb.values for emb in result.embeddings])
535
+ all_embeddings.extend(
536
+ [emb.values for emb in result.embeddings] # type: ignore
537
+ )
536
538
 
537
539
  return all_embeddings
538
540
 
@@ -1,6 +1,8 @@
1
1
  import logging
2
+ import os
2
3
  import os.path
3
- from typing import no_type_check
4
+ import threading
5
+ from typing import ClassVar, Dict, no_type_check
4
6
 
5
7
  import colorlog
6
8
  from rich.console import Console
@@ -114,22 +116,86 @@ def setup_loggers_for_package(package_name: str, level: int) -> None:
114
116
 
115
117
 
116
118
  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
119
+ """Singleton-per-path, ref-counted, thread-safe file logger.
127
120
 
121
+ • Any number of calls to `RichFileLogger(path)` yield the same object.
122
+ • A per-instance lock guarantees that the underlying file is opened only
123
+ once, even when many threads construct the logger concurrently.
124
+ • A reference counter tracks how many parts of the program are using the
125
+ logger; the FD is closed only when the counter reaches zero.
126
+ • All writes are serialised with a dedicated write-lock.
127
+ """
128
+
129
+ _instances: ClassVar[Dict[str, "RichFileLogger"]] = {}
130
+ _ref_counts: ClassVar[Dict[str, int]] = {}
131
+ # guards _instances & _ref_counts
132
+ _class_lock: ClassVar[threading.Lock] = threading.Lock()
133
+
134
+ # ------------------------------------------------------------------ #
135
+ # construction / destruction
136
+ # ------------------------------------------------------------------ #
137
+ def __new__(
138
+ cls, log_file: str, append: bool = False, color: bool = True
139
+ ) -> "RichFileLogger":
140
+ with cls._class_lock:
141
+ if log_file in cls._instances:
142
+ cls._ref_counts[log_file] += 1
143
+ return cls._instances[log_file]
144
+
145
+ inst = super().__new__(cls)
146
+ # create the per-instance init-lock *before* releasing class-lock
147
+ inst._init_lock = threading.Lock()
148
+ cls._instances[log_file] = inst
149
+ cls._ref_counts[log_file] = 1
150
+ return inst
151
+
152
+ def __init__(self, log_file: str, append: bool = False, color: bool = True) -> None:
153
+ # Double-checked locking: perform heavy init exactly once.
154
+ if getattr(self, "_init_done", False):
155
+ return
156
+
157
+ if not hasattr(self, "_init_lock"):
158
+ self._init_lock: threading.Lock = threading.Lock()
159
+
160
+ with self._init_lock:
161
+ if getattr(self, "_init_done", False):
162
+ return
163
+
164
+ os.makedirs(os.path.dirname(log_file), exist_ok=True)
165
+ mode = "a" if append else "w"
166
+ self.file = open(log_file, mode, buffering=1, encoding="utf-8")
167
+ self.log_file: str = log_file
168
+ self.color: bool = color
169
+ self.console: Console | None = (
170
+ Console(file=self.file, force_terminal=True, width=200)
171
+ if color
172
+ else None
173
+ )
174
+ self._write_lock = threading.Lock()
175
+ self._init_done = True # set last
176
+
177
+ # ------------------------------------------------------------------ #
178
+ # public API
179
+ # ------------------------------------------------------------------ #
128
180
  @no_type_check
129
181
  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))
182
+ """Thread-safe write to the log file."""
183
+ with self._write_lock:
184
+ if self.color and self.console is not None:
185
+ self.console.print(escape(message))
186
+ else:
187
+ print(message, file=self.file)
188
+ self.file.flush()
189
+
190
+ def close(self) -> None:
191
+ """Decrease ref-count; close FD only when last user is done."""
192
+ with self._class_lock:
193
+ count = self._ref_counts.get(self.log_file, 0) - 1
194
+ if count <= 0:
195
+ self._ref_counts.pop(self.log_file, None)
196
+ self._instances.pop(self.log_file, None)
197
+ with self._write_lock:
198
+ if not self.file.closed:
199
+ self.file.close()
134
200
  else:
135
- print(message, file=f)
201
+ self._ref_counts[self.log_file] = count
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "langroid"
3
- version = "0.53.10"
3
+ version = "0.53.12"
4
4
  authors = [
5
5
  {name = "Prasad Chalasani", email = "pchalasani@gmail.com"},
6
6
  ]
File without changes
File without changes
File without changes
File without changes