langroid 0.42.8__tar.gz → 0.42.10__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 (134) hide show
  1. {langroid-0.42.8 → langroid-0.42.10}/.gitignore +2 -0
  2. {langroid-0.42.8 → langroid-0.42.10}/PKG-INFO +1 -1
  3. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/base.py +23 -13
  4. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/chat_agent.py +6 -1
  5. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/task.py +4 -1
  6. {langroid-0.42.8 → langroid-0.42.10}/langroid/language_models/openai_gpt.py +32 -31
  7. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/document_parser.py +4 -2
  8. {langroid-0.42.8 → langroid-0.42.10}/pyproject.toml +1 -1
  9. {langroid-0.42.8 → langroid-0.42.10}/LICENSE +0 -0
  10. {langroid-0.42.8 → langroid-0.42.10}/README.md +0 -0
  11. {langroid-0.42.8 → langroid-0.42.10}/langroid/__init__.py +0 -0
  12. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/__init__.py +0 -0
  13. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/batch.py +0 -0
  14. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/callbacks/__init__.py +0 -0
  15. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/callbacks/chainlit.py +0 -0
  16. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/chat_document.py +0 -0
  17. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/openai_assistant.py +0 -0
  18. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/__init__.py +0 -0
  19. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/arangodb/__init__.py +0 -0
  20. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/arangodb/arangodb_agent.py +0 -0
  21. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/arangodb/system_messages.py +0 -0
  22. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/arangodb/tools.py +0 -0
  23. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/arangodb/utils.py +0 -0
  24. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/doc_chat_agent.py +0 -0
  25. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/lance_doc_chat_agent.py +0 -0
  26. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/lance_rag/__init__.py +0 -0
  27. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/lance_rag/critic_agent.py +0 -0
  28. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/lance_rag/lance_rag_task.py +0 -0
  29. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/lance_rag/query_planner_agent.py +0 -0
  30. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/lance_tools.py +0 -0
  31. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/neo4j/__init__.py +0 -0
  32. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/neo4j/csv_kg_chat.py +0 -0
  33. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/neo4j/neo4j_chat_agent.py +0 -0
  34. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/neo4j/system_messages.py +0 -0
  35. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/neo4j/tools.py +0 -0
  36. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/relevance_extractor_agent.py +0 -0
  37. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/retriever_agent.py +0 -0
  38. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/sql/__init__.py +0 -0
  39. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/sql/sql_chat_agent.py +0 -0
  40. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/sql/utils/__init__.py +0 -0
  41. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/sql/utils/description_extractors.py +0 -0
  42. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/sql/utils/populate_metadata.py +0 -0
  43. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/sql/utils/system_message.py +0 -0
  44. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/sql/utils/tools.py +0 -0
  45. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/special/table_chat_agent.py +0 -0
  46. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tool_message.py +0 -0
  47. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tools/__init__.py +0 -0
  48. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tools/duckduckgo_search_tool.py +0 -0
  49. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tools/exa_search_tool.py +0 -0
  50. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tools/file_tools.py +0 -0
  51. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tools/google_search_tool.py +0 -0
  52. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tools/metaphor_search_tool.py +0 -0
  53. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tools/orchestration.py +0 -0
  54. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tools/recipient_tool.py +0 -0
  55. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tools/retrieval_tool.py +0 -0
  56. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tools/rewind_tool.py +0 -0
  57. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tools/segment_extract_tool.py +0 -0
  58. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/tools/tavily_search_tool.py +0 -0
  59. {langroid-0.42.8 → langroid-0.42.10}/langroid/agent/xml_tool_message.py +0 -0
  60. {langroid-0.42.8 → langroid-0.42.10}/langroid/cachedb/__init__.py +0 -0
  61. {langroid-0.42.8 → langroid-0.42.10}/langroid/cachedb/base.py +0 -0
  62. {langroid-0.42.8 → langroid-0.42.10}/langroid/cachedb/momento_cachedb.py +0 -0
  63. {langroid-0.42.8 → langroid-0.42.10}/langroid/cachedb/redis_cachedb.py +0 -0
  64. {langroid-0.42.8 → langroid-0.42.10}/langroid/embedding_models/__init__.py +0 -0
  65. {langroid-0.42.8 → langroid-0.42.10}/langroid/embedding_models/base.py +0 -0
  66. {langroid-0.42.8 → langroid-0.42.10}/langroid/embedding_models/models.py +0 -0
  67. {langroid-0.42.8 → langroid-0.42.10}/langroid/embedding_models/protoc/__init__.py +0 -0
  68. {langroid-0.42.8 → langroid-0.42.10}/langroid/embedding_models/protoc/embeddings.proto +0 -0
  69. {langroid-0.42.8 → langroid-0.42.10}/langroid/embedding_models/protoc/embeddings_pb2.py +0 -0
  70. {langroid-0.42.8 → langroid-0.42.10}/langroid/embedding_models/protoc/embeddings_pb2.pyi +0 -0
  71. {langroid-0.42.8 → langroid-0.42.10}/langroid/embedding_models/protoc/embeddings_pb2_grpc.py +0 -0
  72. {langroid-0.42.8 → langroid-0.42.10}/langroid/embedding_models/remote_embeds.py +0 -0
  73. {langroid-0.42.8 → langroid-0.42.10}/langroid/exceptions.py +0 -0
  74. {langroid-0.42.8 → langroid-0.42.10}/langroid/language_models/__init__.py +0 -0
  75. {langroid-0.42.8 → langroid-0.42.10}/langroid/language_models/azure_openai.py +0 -0
  76. {langroid-0.42.8 → langroid-0.42.10}/langroid/language_models/base.py +0 -0
  77. {langroid-0.42.8 → langroid-0.42.10}/langroid/language_models/config.py +0 -0
  78. {langroid-0.42.8 → langroid-0.42.10}/langroid/language_models/mock_lm.py +0 -0
  79. {langroid-0.42.8 → langroid-0.42.10}/langroid/language_models/model_info.py +0 -0
  80. {langroid-0.42.8 → langroid-0.42.10}/langroid/language_models/prompt_formatter/__init__.py +0 -0
  81. {langroid-0.42.8 → langroid-0.42.10}/langroid/language_models/prompt_formatter/base.py +0 -0
  82. {langroid-0.42.8 → langroid-0.42.10}/langroid/language_models/prompt_formatter/hf_formatter.py +0 -0
  83. {langroid-0.42.8 → langroid-0.42.10}/langroid/language_models/prompt_formatter/llama2_formatter.py +0 -0
  84. {langroid-0.42.8 → langroid-0.42.10}/langroid/language_models/utils.py +0 -0
  85. {langroid-0.42.8 → langroid-0.42.10}/langroid/mytypes.py +0 -0
  86. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/__init__.py +0 -0
  87. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/agent_chats.py +0 -0
  88. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/code_parser.py +0 -0
  89. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/para_sentence_split.py +0 -0
  90. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/parse_json.py +0 -0
  91. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/parser.py +0 -0
  92. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/pdf_utils.py +0 -0
  93. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/repo_loader.py +0 -0
  94. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/routing.py +0 -0
  95. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/search.py +0 -0
  96. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/spider.py +0 -0
  97. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/table_loader.py +0 -0
  98. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/url_loader.py +0 -0
  99. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/urls.py +0 -0
  100. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/utils.py +0 -0
  101. {langroid-0.42.8 → langroid-0.42.10}/langroid/parsing/web_search.py +0 -0
  102. {langroid-0.42.8 → langroid-0.42.10}/langroid/prompts/__init__.py +0 -0
  103. {langroid-0.42.8 → langroid-0.42.10}/langroid/prompts/dialog.py +0 -0
  104. {langroid-0.42.8 → langroid-0.42.10}/langroid/prompts/prompts_config.py +0 -0
  105. {langroid-0.42.8 → langroid-0.42.10}/langroid/prompts/templates.py +0 -0
  106. {langroid-0.42.8 → langroid-0.42.10}/langroid/py.typed +0 -0
  107. {langroid-0.42.8 → langroid-0.42.10}/langroid/pydantic_v1/__init__.py +0 -0
  108. {langroid-0.42.8 → langroid-0.42.10}/langroid/pydantic_v1/main.py +0 -0
  109. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/__init__.py +0 -0
  110. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/algorithms/__init__.py +0 -0
  111. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/algorithms/graph.py +0 -0
  112. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/configuration.py +0 -0
  113. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/constants.py +0 -0
  114. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/git_utils.py +0 -0
  115. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/globals.py +0 -0
  116. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/logging.py +0 -0
  117. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/object_registry.py +0 -0
  118. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/output/__init__.py +0 -0
  119. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/output/citations.py +0 -0
  120. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/output/printing.py +0 -0
  121. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/output/status.py +0 -0
  122. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/pandas_utils.py +0 -0
  123. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/pydantic_utils.py +0 -0
  124. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/system.py +0 -0
  125. {langroid-0.42.8 → langroid-0.42.10}/langroid/utils/types.py +0 -0
  126. {langroid-0.42.8 → langroid-0.42.10}/langroid/vector_store/__init__.py +0 -0
  127. {langroid-0.42.8 → langroid-0.42.10}/langroid/vector_store/base.py +0 -0
  128. {langroid-0.42.8 → langroid-0.42.10}/langroid/vector_store/chromadb.py +0 -0
  129. {langroid-0.42.8 → langroid-0.42.10}/langroid/vector_store/lancedb.py +0 -0
  130. {langroid-0.42.8 → langroid-0.42.10}/langroid/vector_store/meilisearch.py +0 -0
  131. {langroid-0.42.8 → langroid-0.42.10}/langroid/vector_store/pineconedb.py +0 -0
  132. {langroid-0.42.8 → langroid-0.42.10}/langroid/vector_store/postgres.py +0 -0
  133. {langroid-0.42.8 → langroid-0.42.10}/langroid/vector_store/qdrantdb.py +0 -0
  134. {langroid-0.42.8 → langroid-0.42.10}/langroid/vector_store/weaviatedb.py +0 -0
@@ -135,6 +135,8 @@ dmypy.json
135
135
  # Pyre type checker
136
136
  .pyre/
137
137
 
138
+ # Chainlit
139
+ .chainlit/
138
140
 
139
141
  .vscode
140
142
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langroid
3
- Version: 0.42.8
3
+ Version: 0.42.10
4
4
  Summary: Harness LLMs with Multi-Agent Programming
5
5
  Author-email: Prasad Chalasani <pchalasani@gmail.com>
6
6
  License: MIT
@@ -1148,7 +1148,9 @@ class Agent(ABC):
1148
1148
  and msg.function_call is None
1149
1149
  ):
1150
1150
 
1151
- tools = self.get_formatted_tool_messages(msg.content)
1151
+ tools = self.get_formatted_tool_messages(
1152
+ msg.content, from_llm=msg.metadata.sender == Entity.LLM
1153
+ )
1152
1154
  msg.all_tool_messages = tools
1153
1155
  # filter for actually handle-able tools, and recipient is this agent
1154
1156
  my_tools = [t for t in tools if self._tool_recipient_match(t)]
@@ -1177,7 +1179,9 @@ class Agent(ABC):
1177
1179
  else:
1178
1180
  return my_tools
1179
1181
 
1180
- def get_formatted_tool_messages(self, input_str: str) -> List[ToolMessage]:
1182
+ def get_formatted_tool_messages(
1183
+ self, input_str: str, from_llm: bool = True
1184
+ ) -> List[ToolMessage]:
1181
1185
  """
1182
1186
  Returns ToolMessage objects (tools) corresponding to
1183
1187
  tool-formatted substrings, if any.
@@ -1190,6 +1194,8 @@ class Agent(ABC):
1190
1194
 
1191
1195
  Args:
1192
1196
  input_str (str): input string, typically a message sent by an LLM
1197
+ from_llm (bool): whether the input was generated by the LLM. If so,
1198
+ we track malformed tool calls.
1193
1199
 
1194
1200
  Returns:
1195
1201
  List[ToolMessage]: list of ToolMessage objects
@@ -1203,7 +1209,7 @@ class Agent(ABC):
1203
1209
  if not is_json:
1204
1210
  return []
1205
1211
 
1206
- results = [self._get_one_tool_message(j, is_json) for j in substrings]
1212
+ results = [self._get_one_tool_message(j, is_json, from_llm) for j in substrings]
1207
1213
  valid_results = [r for r in results if r is not None]
1208
1214
  # If any tool is correctly formed we do not set the flag
1209
1215
  if len(valid_results) > 0:
@@ -1219,6 +1225,7 @@ class Agent(ABC):
1219
1225
  return None
1220
1226
  tool_name = msg.function_call.name
1221
1227
  tool_msg = msg.function_call.arguments or {}
1228
+ self.tool_error = False
1222
1229
  if tool_name not in self.llm_tools_handled:
1223
1230
  logger.warning(
1224
1231
  f"""
@@ -1230,10 +1237,12 @@ class Agent(ABC):
1230
1237
  or you need to enable this agent to handle this fn-call.
1231
1238
  """
1232
1239
  )
1233
- if tool_name not in self.all_llm_tools_known:
1240
+ if (
1241
+ tool_name not in self.all_llm_tools_known
1242
+ and msg.metadata.sender == Entity.LLM
1243
+ ):
1234
1244
  self.tool_error = True
1235
1245
  return None
1236
- self.tool_error = False
1237
1246
  tool_class = self.llm_tools_map[tool_name]
1238
1247
  tool_msg.update(dict(request=tool_name))
1239
1248
  tool = tool_class.parse_obj(tool_msg)
@@ -1272,8 +1281,9 @@ class Agent(ABC):
1272
1281
  tool = tool_class.parse_obj(tool_msg)
1273
1282
  tool.id = tc.id or ""
1274
1283
  tools.append(tool)
1275
- # When no tool is valid, set the recovery flag
1276
- self.tool_error = all_errors
1284
+ # When no tool is valid and the message was produced
1285
+ # by the LLM, set the recovery flag
1286
+ self.tool_error = all_errors and msg.metadata.sender == Entity.LLM
1277
1287
  return tools
1278
1288
 
1279
1289
  def tool_validation_error(self, ve: ValidationError) -> str:
@@ -1508,7 +1518,7 @@ class Agent(ABC):
1508
1518
  return None
1509
1519
 
1510
1520
  def _get_one_tool_message(
1511
- self, tool_candidate_str: str, is_json: bool = True
1521
+ self, tool_candidate_str: str, is_json: bool = True, from_llm: bool = True
1512
1522
  ) -> Optional[ToolMessage]:
1513
1523
  """
1514
1524
  Parse the tool_candidate_str into ANY ToolMessage KNOWN to agent --
@@ -1545,7 +1555,7 @@ class Agent(ABC):
1545
1555
  # }
1546
1556
 
1547
1557
  if not isinstance(maybe_tool_dict, dict):
1548
- self.tool_error = True
1558
+ self.tool_error = from_llm
1549
1559
  return None
1550
1560
 
1551
1561
  properties = maybe_tool_dict.get("properties")
@@ -1593,23 +1603,23 @@ class Agent(ABC):
1593
1603
  if len(candidate_tools) == 1:
1594
1604
  return candidate_tools[0]
1595
1605
  else:
1596
- self.tool_error = True
1606
+ self.tool_error = from_llm
1597
1607
  return None
1598
1608
 
1599
1609
  if not isinstance(request, str) or request not in self.all_llm_tools_known:
1600
- self.tool_error = True
1610
+ self.tool_error = from_llm
1601
1611
  return None
1602
1612
 
1603
1613
  message_class = self.llm_tools_map.get(request)
1604
1614
  if message_class is None:
1605
1615
  logger.warning(f"No message class found for request '{request}'")
1606
- self.tool_error = True
1616
+ self.tool_error = from_llm
1607
1617
  return None
1608
1618
 
1609
1619
  try:
1610
1620
  message = message_class.parse_obj(maybe_tool_dict)
1611
1621
  except ValidationError as ve:
1612
- self.tool_error = True
1622
+ self.tool_error = from_llm
1613
1623
  raise ve
1614
1624
  return message
1615
1625
 
@@ -1096,7 +1096,10 @@ class ChatAgent(Agent):
1096
1096
  else:
1097
1097
  # We will trigger the strict recovery mechanism to force
1098
1098
  # the LLM to correct its output, allowing us to parse
1099
- self.tool_error = True
1099
+ if isinstance(msg, ChatDocument):
1100
+ self.tool_error = msg.metadata.sender == Entity.LLM
1101
+ else:
1102
+ self.tool_error = True
1100
1103
 
1101
1104
  raise ve
1102
1105
 
@@ -1265,6 +1268,7 @@ class ChatAgent(Agent):
1265
1268
  and self._json_schema_available()
1266
1269
  and self.config.strict_recovery
1267
1270
  ):
1271
+ self.tool_error = False
1268
1272
  AnyTool = self._get_any_tool_message()
1269
1273
  if AnyTool is None:
1270
1274
  return None
@@ -1352,6 +1356,7 @@ class ChatAgent(Agent):
1352
1356
  and self._json_schema_available()
1353
1357
  and self.config.strict_recovery
1354
1358
  ):
1359
+ self.tool_error = False
1355
1360
  AnyTool = self._get_any_tool_message()
1356
1361
  self.set_output_format(
1357
1362
  AnyTool,
@@ -1572,7 +1572,10 @@ class Task:
1572
1572
  response_fn = self._entity_responder_async_map[cast(Entity, e)]
1573
1573
  result = await response_fn(self.pending_message)
1574
1574
  # update result.tool_messages if any
1575
- if isinstance(result, ChatDocument):
1575
+ if (
1576
+ isinstance(result, ChatDocument)
1577
+ and result.metadata.sender == Entity.LLM
1578
+ ):
1576
1579
  self.agent.try_get_tool_messages(result)
1577
1580
 
1578
1581
  result_chat_doc = self.agent.to_ChatDocument(
@@ -85,9 +85,6 @@ GLHF_BASE_URL = "https://glhf.chat/api/openai/v1"
85
85
  OLLAMA_API_KEY = "ollama"
86
86
  DUMMY_API_KEY = "xxx"
87
87
 
88
- VLLM_API_KEY = os.environ.get("VLLM_API_KEY", DUMMY_API_KEY)
89
- LLAMACPP_API_KEY = os.environ.get("LLAMA_API_KEY", DUMMY_API_KEY)
90
-
91
88
 
92
89
  openai_chat_model_pref_list = [
93
90
  OpenAIChatModel.GPT4o,
@@ -215,11 +212,20 @@ class OpenAIGPTConfig(LLMConfig):
215
212
  (a) locally-served models behind an OpenAI-compatible API
216
213
  (b) non-local models, using a proxy adaptor lib like litellm that provides
217
214
  an OpenAI-compatible API.
218
- We could rename this class to OpenAILikeConfig.
215
+ (We could rename this class to OpenAILikeConfig, but we keep it as-is for now)
216
+
217
+ Important Note:
218
+ Due to the `env_prefix = "OPENAI_"` defined below,
219
+ all of the fields below can be set AND OVERRIDDEN via env vars,
220
+ # by upper-casing the name and prefixing with OPENAI_, e.g.
221
+ # OPENAI_MAX_OUTPUT_TOKENS=1000.
222
+ # If any of these is defined in this way in the environment
223
+ # (either via explicit setenv or export or via .env file + load_dotenv()),
224
+ # the environment variable takes precedence over the value in the config.
219
225
  """
220
226
 
221
227
  type: str = "openai"
222
- api_key: str = DUMMY_API_KEY # CAUTION: set this ONLY via env var OPENAI_API_KEY
228
+ api_key: str = DUMMY_API_KEY
223
229
  organization: str = ""
224
230
  api_base: str | None = None # used for local or other non-OpenAI models
225
231
  litellm: bool = False # use litellm api?
@@ -273,11 +279,6 @@ class OpenAIGPTConfig(LLMConfig):
273
279
 
274
280
  super().__init__(**kwargs)
275
281
 
276
- # all of the vars above can be set via env vars,
277
- # by upper-casing the name and prefixing with OPENAI_, e.g.
278
- # OPENAI_MAX_OUTPUT_TOKENS=1000.
279
- # This is either done in the .env file, or via an explicit
280
- # `export OPENAI_MAX_OUTPUT_TOKENS=1000` or `setenv OPENAI_MAX_OUTPUT_TOKENS 1000`
281
282
  class Config:
282
283
  env_prefix = "OPENAI_"
283
284
 
@@ -417,6 +418,9 @@ class OpenAIGPT(LanguageModel):
417
418
  self.supports_json_schema: bool = self.config.supports_json_schema or False
418
419
  self.supports_strict_tools: bool = self.config.supports_strict_tools or False
419
420
 
421
+ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", DUMMY_API_KEY)
422
+ self.api_key = config.api_key
423
+
420
424
  # if model name starts with "litellm",
421
425
  # set the actual model name by stripping the "litellm/" prefix
422
426
  # and set the litellm flag to True
@@ -445,12 +449,14 @@ class OpenAIGPT(LanguageModel):
445
449
 
446
450
  # use api_base from config if set, else fall back on OLLAMA_BASE_URL
447
451
  self.api_base = self.config.api_base or OLLAMA_BASE_URL
448
- self.api_key = OLLAMA_API_KEY
452
+ if self.api_key == OPENAI_API_KEY:
453
+ self.api_key = OLLAMA_API_KEY
449
454
  self.config.chat_model = self.config.chat_model.replace("ollama/", "")
450
455
  elif self.config.chat_model.startswith("vllm/"):
451
456
  self.supports_json_schema = True
452
457
  self.config.chat_model = self.config.chat_model.replace("vllm/", "")
453
- self.api_key = VLLM_API_KEY
458
+ if self.api_key == OPENAI_API_KEY:
459
+ self.api_key = os.environ.get("VLLM_API_KEY", DUMMY_API_KEY)
454
460
  self.api_base = self.config.api_base or "http://localhost:8000/v1"
455
461
  if not self.api_base.startswith("http"):
456
462
  self.api_base = "http://" + self.api_base
@@ -461,7 +467,8 @@ class OpenAIGPT(LanguageModel):
461
467
  self.api_base = self.config.chat_model.split("/", 1)[1]
462
468
  if not self.api_base.startswith("http"):
463
469
  self.api_base = "http://" + self.api_base
464
- self.api_key = LLAMACPP_API_KEY
470
+ if self.api_key == OPENAI_API_KEY:
471
+ self.api_key = os.environ.get("LLAMA_API_KEY", DUMMY_API_KEY)
465
472
  else:
466
473
  self.api_base = self.config.api_base
467
474
  # If api_base is unset we use OpenAI's endpoint, which supports
@@ -483,18 +490,6 @@ class OpenAIGPT(LanguageModel):
483
490
  if self.config.use_completion_for_chat:
484
491
  self.config.use_chat_for_completion = False
485
492
 
486
- # NOTE: The api_key should be set in the .env file, or via
487
- # an explicit `export OPENAI_API_KEY=xxx` or `setenv OPENAI_API_KEY xxx`
488
- # Pydantic's BaseSettings will automatically pick it up from the
489
- # .env file
490
- # The config.api_key is ignored when not using an OpenAI model
491
- if self.is_openai_completion_model() or self.is_openai_chat_model():
492
- self.api_key = config.api_key
493
- if self.api_key == DUMMY_API_KEY:
494
- self.api_key = os.getenv("OPENAI_API_KEY", DUMMY_API_KEY)
495
- else:
496
- self.api_key = DUMMY_API_KEY
497
-
498
493
  self.is_groq = self.config.chat_model.startswith("groq/")
499
494
  self.is_cerebras = self.config.chat_model.startswith("cerebras/")
500
495
  self.is_gemini = self.is_gemini_model()
@@ -505,7 +500,8 @@ class OpenAIGPT(LanguageModel):
505
500
  if self.is_groq:
506
501
  # use groq-specific client
507
502
  self.config.chat_model = self.config.chat_model.replace("groq/", "")
508
- self.api_key = os.getenv("GROQ_API_KEY", DUMMY_API_KEY)
503
+ if self.api_key == OPENAI_API_KEY:
504
+ self.api_key = os.getenv("GROQ_API_KEY", DUMMY_API_KEY)
509
505
  self.client = Groq(
510
506
  api_key=self.api_key,
511
507
  )
@@ -515,7 +511,8 @@ class OpenAIGPT(LanguageModel):
515
511
  elif self.is_cerebras:
516
512
  # use cerebras-specific client
517
513
  self.config.chat_model = self.config.chat_model.replace("cerebras/", "")
518
- self.api_key = os.getenv("CEREBRAS_API_KEY", DUMMY_API_KEY)
514
+ if self.api_key == OPENAI_API_KEY:
515
+ self.api_key = os.getenv("CEREBRAS_API_KEY", DUMMY_API_KEY)
519
516
  self.client = Cerebras(
520
517
  api_key=self.api_key,
521
518
  )
@@ -527,22 +524,26 @@ class OpenAIGPT(LanguageModel):
527
524
  # in these cases, there's no specific client: OpenAI python client suffices
528
525
  if self.is_gemini:
529
526
  self.config.chat_model = self.config.chat_model.replace("gemini/", "")
530
- self.api_key = os.getenv("GEMINI_API_KEY", DUMMY_API_KEY)
527
+ if self.api_key == OPENAI_API_KEY:
528
+ self.api_key = os.getenv("GEMINI_API_KEY", DUMMY_API_KEY)
531
529
  self.api_base = GEMINI_BASE_URL
532
530
  elif self.is_glhf:
533
531
  self.config.chat_model = self.config.chat_model.replace("glhf/", "")
534
- self.api_key = os.getenv("GLHF_API_KEY", DUMMY_API_KEY)
532
+ if self.api_key == OPENAI_API_KEY:
533
+ self.api_key = os.getenv("GLHF_API_KEY", DUMMY_API_KEY)
535
534
  self.api_base = GLHF_BASE_URL
536
535
  elif self.is_openrouter:
537
536
  self.config.chat_model = self.config.chat_model.replace(
538
537
  "openrouter/", ""
539
538
  )
540
- self.api_key = os.getenv("OPENROUTER_API_KEY", DUMMY_API_KEY)
539
+ if self.api_key == OPENAI_API_KEY:
540
+ self.api_key = os.getenv("OPENROUTER_API_KEY", DUMMY_API_KEY)
541
541
  self.api_base = OPENROUTER_BASE_URL
542
542
  elif self.is_deepseek:
543
543
  self.config.chat_model = self.config.chat_model.replace("deepseek/", "")
544
544
  self.api_base = DEEPSEEK_BASE_URL
545
- self.api_key = os.getenv("DEEPSEEK_API_KEY", DUMMY_API_KEY)
545
+ if self.api_key == OPENAI_API_KEY:
546
+ self.api_key = os.getenv("DEEPSEEK_API_KEY", DUMMY_API_KEY)
546
547
 
547
548
  self.client = OpenAI(
548
549
  api_key=self.api_key,
@@ -415,13 +415,15 @@ class DocumentParser(Parser):
415
415
  # that it needs to be combined with the next chunk.
416
416
  while len(split) > self.config.chunk_size:
417
417
  # pretty formatting of pages (e.g. 1-3, 4, 5-7)
418
- pg = "-".join([pages[0], pages[-1]])
418
+ p_0 = int(pages[0])
419
+ p_n = int(pages[-1])
420
+ page_str = f"pages {p_0}-{p_n}" if p_0 != p_n else f"page {p_0}"
419
421
  text = self.tokenizer.decode(split[: self.config.chunk_size])
420
422
  docs.append(
421
423
  Document(
422
424
  content=text,
423
425
  metadata=DocMetaData(
424
- source=f"{self.source} pages {pg}",
426
+ source=f"{self.source} {page_str}",
425
427
  is_chunk=True,
426
428
  id=common_id,
427
429
  ),
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "langroid"
3
- version = "0.42.8"
3
+ version = "0.42.10"
4
4
  authors = [
5
5
  {name = "Prasad Chalasani", email = "pchalasani@gmail.com"},
6
6
  ]
File without changes
File without changes
File without changes