langroid 0.41.2__py3-none-any.whl → 0.41.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/agent/base.py CHANGED
@@ -147,8 +147,7 @@ class Agent(ABC):
147
147
  self.llm_tools_usable: Set[str] = set()
148
148
  self.llm_tools_known: Set[str] = set() # all known tools, handled/used or not
149
149
  # Indicates which tool-names are allowed to be inferred when
150
- # the LLM "forgets" to include the request field in its
151
- # tool-call.
150
+ # the LLM "forgets" to include the request field in its tool-call.
152
151
  self.enabled_requests_for_inference: Optional[Set[str]] = (
153
152
  None # If None, we allow all
154
153
  )
@@ -37,6 +37,7 @@ from langroid.utils.configuration import settings
37
37
  from langroid.utils.object_registry import ObjectRegistry
38
38
  from langroid.utils.output import status
39
39
  from langroid.utils.pydantic_utils import PydanticWrapper, get_pydantic_wrapper
40
+ from langroid.utils.types import is_callable
40
41
 
41
42
  console = Console()
42
43
 
@@ -613,6 +614,8 @@ class ChatAgent(Agent):
613
614
  return AgentDoneTool(
614
615
  content=msg.content, tools=msg.tool_messages
615
616
  )
617
+ elif is_callable(no_tool_option):
618
+ return no_tool_option(msg)
616
619
  # Otherwise just return `no_tool_option` as is:
617
620
  # This can be any string, such as a specific nudge/reminder to the LLM,
618
621
  # or even something like ResultTool etc.
@@ -450,9 +450,9 @@ class LlamaCppServerEmbeddings(EmbeddingModel):
450
450
  class GeminiEmbeddings(EmbeddingModel):
451
451
  def __init__(self, config: GeminiEmbeddingsConfig = GeminiEmbeddingsConfig()):
452
452
  try:
453
- import google.generativeai as genai
453
+ from google import genai
454
454
  except ImportError as e:
455
- raise LangroidImportError(extra="google-generativeai", error=str(e))
455
+ raise LangroidImportError(extra="google-genai", error=str(e))
456
456
  super().__init__()
457
457
  self.config = config
458
458
  load_dotenv()
@@ -464,29 +464,30 @@ class GeminiEmbeddings(EmbeddingModel):
464
464
  GEMINI_API_KEY env variable must be set to use GeminiEmbeddings.
465
465
  """
466
466
  )
467
- genai.configure(api_key=self.config.api_key) # type: ignore[attr-defined]
468
- self.client = genai
467
+ self.client = genai.Client(api_key=self.config.api_key)
469
468
 
470
469
  def embedding_fn(self) -> Callable[[List[str]], Embeddings]:
471
470
  return EmbeddingFunctionCallable(self, self.config.batch_size)
472
471
 
473
- def generate_embeddings(self, texts: List[str]) -> Embeddings:
474
- all_embeddings = [] # More precise type hint
472
+ def generate_embeddings(self, texts: List[str]) -> List[List[float]]:
473
+ """Generates embeddings for a list of input texts."""
474
+ all_embeddings: List[List[float]] = []
475
+
475
476
  for batch in batched(texts, self.config.batch_size):
476
- result = self.client.embed_content( # type: ignore[attr-defined]
477
+ result = self.client.models.embed_content( # type: ignore[attr-defined]
477
478
  model=self.config.model_name,
478
- content=batch,
479
- task_type="RETRIEVAL_DOCUMENT",
479
+ contents=batch,
480
480
  )
481
481
 
482
- embeddings = result["embedding"]
483
- if not isinstance(embeddings, list):
484
- raise ValueError("Unexpected format for embeddings: not a list")
482
+ if not hasattr(result, "embeddings") or not isinstance(
483
+ result.embeddings, list
484
+ ):
485
+ raise ValueError(
486
+ "Unexpected format for embeddings: missing or incorrect type"
487
+ )
485
488
 
486
- if embeddings and isinstance(embeddings[0], list):
487
- all_embeddings.extend(embeddings)
488
- else:
489
- all_embeddings.append(embeddings)
489
+ # Extract .values from ContentEmbedding objects
490
+ all_embeddings.extend([emb.values for emb in result.embeddings])
490
491
 
491
492
  return all_embeddings
492
493
 
@@ -19,7 +19,7 @@ from typing import (
19
19
 
20
20
  from langroid.cachedb.base import CacheDBConfig
21
21
  from langroid.cachedb.redis_cachedb import RedisCacheConfig
22
- from langroid.language_models.model_info import get_model_info
22
+ from langroid.language_models.model_info import ModelInfo, get_model_info
23
23
  from langroid.parsing.agent_chats import parse_message
24
24
  from langroid.parsing.parse_json import parse_imperfect_json, top_level_json_field
25
25
  from langroid.prompts.dialog import collate_chat_history
@@ -425,6 +425,7 @@ class LanguageModel(ABC):
425
425
 
426
426
  def __init__(self, config: LLMConfig = LLMConfig()):
427
427
  self.config = config
428
+ self.chat_model_orig = config.chat_model
428
429
 
429
430
  @staticmethod
430
431
  def create(config: Optional[LLMConfig]) -> Optional["LanguageModel"]:
@@ -595,6 +596,34 @@ class LanguageModel(ABC):
595
596
  def __call__(self, prompt: str, max_tokens: int) -> LLMResponse:
596
597
  return self.generate(prompt, max_tokens)
597
598
 
599
+ def info(self) -> ModelInfo:
600
+ """Info of relevant chat model"""
601
+ model = (
602
+ self.config.completion_model
603
+ if self.config.use_completion_for_chat
604
+ else self.config.chat_model
605
+ )
606
+ orig_model = (
607
+ self.config.completion_model
608
+ if self.config.use_completion_for_chat
609
+ else self.chat_model_orig
610
+ )
611
+ return get_model_info(orig_model, model)
612
+
613
+ def completion_info(self) -> ModelInfo:
614
+ """Info of relevant completion model"""
615
+ model = (
616
+ self.config.chat_model
617
+ if self.config.use_chat_for_completion
618
+ else self.config.completion_model
619
+ )
620
+ orig_model = (
621
+ self.chat_model_orig
622
+ if self.config.use_chat_for_completion
623
+ else self.config.completion_model
624
+ )
625
+ return get_model_info(orig_model, model)
626
+
598
627
  def chat_context_length(self) -> int:
599
628
  return self.config.chat_context_length
600
629
 
@@ -50,7 +50,6 @@ from langroid.language_models.model_info import (
50
50
  DeepSeekModel,
51
51
  GeminiModel,
52
52
  OpenAI_API_ParamInfo,
53
- get_model_info,
54
53
  )
55
54
  from langroid.language_models.model_info import (
56
55
  OpenAIChatModel as OpenAIChatModel,
@@ -233,6 +232,7 @@ class OpenAIGPTConfig(LLMConfig):
233
232
  params: OpenAICallParams | None = None
234
233
  # these can be any model name that is served at an OpenAI-compatible API end point
235
234
  chat_model: str = default_openai_chat_model
235
+ chat_model_orig: str = default_openai_chat_model
236
236
  completion_model: str = default_openai_completion_model
237
237
  run_on_first_use: Callable[[], None] = noop
238
238
  parallel_tool_calls: Optional[bool] = None
@@ -372,7 +372,8 @@ class OpenAIGPT(LanguageModel):
372
372
  super().__init__(config)
373
373
  self.config: OpenAIGPTConfig = config
374
374
  # save original model name such as `provider/model` before
375
- # we strip out the `provider`
375
+ # we strip out the `provider` - we retain the original in
376
+ # case some params are specific to a provider.
376
377
  self.chat_model_orig = self.config.chat_model
377
378
 
378
379
  # Run the first time the model is used
@@ -467,11 +468,7 @@ class OpenAIGPT(LanguageModel):
467
468
  # these features (with JSON schema restricted to a limited set of models)
468
469
  self.supports_strict_tools = self.api_base is None
469
470
  self.supports_json_schema = (
470
- self.api_base is None
471
- and get_model_info( # look for family/provider-specific then generic
472
- self.chat_model_orig, # e.g. "gemini/gemini-2.0-flash"
473
- self.config.chat_model, # e.g. "gemini-2.0-flash"
474
- ).has_structured_output
471
+ self.api_base is None and self.info().has_structured_output
475
472
  )
476
473
 
477
474
  if settings.chat_model != "":
@@ -621,13 +618,7 @@ class OpenAIGPT(LanguageModel):
621
618
  return self.config.chat_model in openai_chat_models
622
619
 
623
620
  def supports_functions_or_tools(self) -> bool:
624
- return (
625
- self.is_openai_chat_model()
626
- and get_model_info(
627
- self.chat_model_orig,
628
- self.config.chat_model,
629
- ).has_tools
630
- )
621
+ return self.is_openai_chat_model() and self.info().has_tools
631
622
 
632
623
  def is_openai_completion_model(self) -> bool:
633
624
  openai_completion_models = [e.value for e in OpenAICompletionModel]
@@ -650,11 +641,7 @@ class OpenAIGPT(LanguageModel):
650
641
  """
651
642
  List of params that are not supported by the current model
652
643
  """
653
- model_info = get_model_info(
654
- self.chat_model_orig,
655
- self.config.chat_model,
656
- )
657
- unsupported = set(model_info.unsupported_params)
644
+ unsupported = set(self.info().unsupported_params)
658
645
  for param, model_list in OpenAI_API_ParamInfo().params.items():
659
646
  if (
660
647
  self.config.chat_model not in model_list
@@ -668,44 +655,21 @@ class OpenAIGPT(LanguageModel):
668
655
  Map of param name -> new name for specific models.
669
656
  Currently main troublemaker is o1* series.
670
657
  """
671
- return get_model_info(
672
- self.chat_model_orig,
673
- self.config.chat_model,
674
- ).rename_params
658
+ return self.info().rename_params
675
659
 
676
660
  def chat_context_length(self) -> int:
677
661
  """
678
662
  Context-length for chat-completion models/endpoints
679
663
  Get it from the dict, otherwise fail-over to general method
680
664
  """
681
- model = (
682
- self.config.completion_model
683
- if self.config.use_completion_for_chat
684
- else self.config.chat_model
685
- )
686
- orig_model = (
687
- self.config.completion_model
688
- if self.config.use_completion_for_chat
689
- else self.chat_model_orig
690
- )
691
- return get_model_info(orig_model, model).context_length
665
+ return self.info().context_length
692
666
 
693
667
  def completion_context_length(self) -> int:
694
668
  """
695
669
  Context-length for completion models/endpoints
696
670
  Get it from the dict, otherwise fail-over to general method
697
671
  """
698
- model = (
699
- self.config.chat_model
700
- if self.config.use_chat_for_completion
701
- else self.config.completion_model
702
- )
703
- orig_model = (
704
- self.chat_model_orig
705
- if self.config.use_chat_for_completion
706
- else self.config.completion_model
707
- )
708
- return get_model_info(orig_model, model).context_length
672
+ return self.completion_info().context_length
709
673
 
710
674
  def chat_cost(self) -> Tuple[float, float]:
711
675
  """
@@ -713,7 +677,7 @@ class OpenAIGPT(LanguageModel):
713
677
  models/endpoints.
714
678
  Get it from the dict, otherwise fail-over to general method
715
679
  """
716
- info = get_model_info(self.config.chat_model)
680
+ info = self.info()
717
681
  return (info.input_cost_per_million / 1000, info.output_cost_per_million / 1000)
718
682
 
719
683
  def set_stream(self, stream: bool) -> bool:
@@ -731,10 +695,7 @@ class OpenAIGPT(LanguageModel):
731
695
  return (
732
696
  self.config.stream
733
697
  and settings.stream
734
- and get_model_info(
735
- self.chat_model_orig,
736
- self.config.chat_model,
737
- ).allows_streaming
698
+ and self.info().allows_streaming
738
699
  and not settings.quiet
739
700
  )
740
701
 
@@ -1744,11 +1705,7 @@ class OpenAIGPT(LanguageModel):
1744
1705
  args: Dict[str, Any] = dict(
1745
1706
  model=chat_model,
1746
1707
  messages=[
1747
- m.api_dict(
1748
- has_system_role=get_model_info(
1749
- self.config.chat_model
1750
- ).allows_system_message
1751
- )
1708
+ m.api_dict(has_system_role=self.info().allows_system_message)
1752
1709
  for m in (llm_messages)
1753
1710
  ],
1754
1711
  max_tokens=max_tokens,
langroid/utils/types.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import json
2
2
  import logging
3
+ from inspect import signature
3
4
  from typing import Any, Optional, Type, TypeVar, Union, get_args, get_origin
4
5
 
5
6
  from langroid.pydantic_v1 import BaseModel
@@ -91,3 +92,22 @@ def from_string(
91
92
  return s
92
93
  else:
93
94
  return None
95
+
96
+
97
+ def is_callable(obj: Any, k: int = 1) -> bool:
98
+ """Check if object is callable and accepts exactly k args.
99
+
100
+ Args:
101
+ obj: Object to check
102
+
103
+ Returns:
104
+ bool: True if object is callable with k args, False otherwise
105
+ """
106
+ if not callable(obj):
107
+ return False
108
+ try:
109
+ sig = signature(obj)
110
+ params = list(sig.parameters.values())
111
+ return len(params) == k
112
+ except ValueError:
113
+ return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langroid
3
- Version: 0.41.2
3
+ Version: 0.41.4
4
4
  Summary: Harness LLMs with Multi-Agent Programming
5
5
  Author-email: Prasad Chalasani <pchalasani@gmail.com>
6
6
  License: MIT
@@ -21,7 +21,7 @@ Requires-Dist: fakeredis<3.0.0,>=2.12.1
21
21
  Requires-Dist: fire<1.0.0,>=0.5.0
22
22
  Requires-Dist: gitpython<4.0.0,>=3.1.43
23
23
  Requires-Dist: google-api-python-client<3.0.0,>=2.95.0
24
- Requires-Dist: google-generativeai<1.0.0,>=0.5.2
24
+ Requires-Dist: google-genai>=1.0.0
25
25
  Requires-Dist: groq<1.0.0,>=0.13.0
26
26
  Requires-Dist: grpcio<2.0.0,>=1.62.1
27
27
  Requires-Dist: halo<1.0.0,>=0.0.31
@@ -112,8 +112,10 @@ Provides-Extra: exa
112
112
  Requires-Dist: exa-py>=1.8.7; extra == 'exa'
113
113
  Provides-Extra: fastembed
114
114
  Requires-Dist: fastembed<0.4.0,>=0.3.1; extra == 'fastembed'
115
+ Provides-Extra: google-genai
116
+ Requires-Dist: google-genai>=1.0.0; extra == 'google-genai'
115
117
  Provides-Extra: google-generativeai
116
- Requires-Dist: google-generativeai>=0.8.4; extra == 'google-generativeai'
118
+ Requires-Dist: google-genai>=1.0.0; extra == 'google-generativeai'
117
119
  Provides-Extra: hf-embeddings
118
120
  Requires-Dist: sentence-transformers<3.0.0,>=2.2.2; extra == 'hf-embeddings'
119
121
  Requires-Dist: torch<3.0.0,>=2.0.0; extra == 'hf-embeddings'
@@ -319,7 +321,7 @@ teacher_task.run()
319
321
  - **Jan 2025:**
320
322
  - [0.36.0](https://github.com/langroid/langroid/releases/tag/0.36.0): Weaviate vector-db support (thanks @abab-dev).
321
323
  - [0.35.0](https://github.com/langroid/langroid/releases/tag/0.35.0): Capture/Stream reasoning content from
322
- Reasoning LLMs (e.g. DeepSeek, OpenAI o1) in addition to final answer.
324
+ Reasoning LLMs (e.g. DeepSeek-R1, OpenAI o1) in addition to final answer.
323
325
  - [0.34.0](https://github.com/langroid/langroid/releases/tag/0.34.0): DocChatAgent
324
326
  chunk enrichment to improve retrieval. (collaboration with @dfm88).
325
327
  - [0.33.0](https://github.com/langroid/langroid/releases/tag/0.33.3) Move from Poetry to uv! (thanks @abab-dev).
@@ -627,7 +629,7 @@ For many practical scenarios, you may need additional optional dependencies:
627
629
  - For "chat with databases", use the `db` extra:
628
630
  ```bash
629
631
  pip install "langroid[db]"
630
- ``
632
+ ```
631
633
  - You can specify multiple extras by separating them with commas, e.g.:
632
634
  ```bash
633
635
  pip install "langroid[doc-chat,db]"
@@ -3,9 +3,9 @@ langroid/exceptions.py,sha256=OPjece_8cwg94DLPcOGA1ddzy5bGh65pxzcHMnssTz8,2995
3
3
  langroid/mytypes.py,sha256=FXSH62MUCeMCJP-66RVmbNaHCDLMxllEShZ-xEeTn9A,2833
4
4
  langroid/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  langroid/agent/__init__.py,sha256=ll0Cubd2DZ-fsCMl7e10hf9ZjFGKzphfBco396IKITY,786
6
- langroid/agent/base.py,sha256=CVPvy-bLI_6wHZxYf_spo4eq-utR373Ur7T3zKpe18U,78222
6
+ langroid/agent/base.py,sha256=k5kJGTpo2CcnVl2cEM0luBQ__a7C9put1aH5-wd3hQ8,78212
7
7
  langroid/agent/batch.py,sha256=vi1r5i1-vN80WfqHDSwjEym_KfGsqPGUtwktmiK1nuk,20635
8
- langroid/agent/chat_agent.py,sha256=q9J5NQzyZZxWX8y-u1xMITJObFN4GlDFS3CEMl39taY,84077
8
+ langroid/agent/chat_agent.py,sha256=hUu13nYhhr6ph01Sln8y_WuOIpcd38icN6p22h6IiDY,84211
9
9
  langroid/agent/chat_document.py,sha256=xzMtrPbaW-Y-BnF7kuhr2dorsD-D5rMWzfOqJ8HAoo8,17885
10
10
  langroid/agent/openai_assistant.py,sha256=JkAcs02bIrgPNVvUWVR06VCthc5-ulla2QMBzux_q6o,34340
11
11
  langroid/agent/task.py,sha256=XrXUbSoiFasvpIsZPn_cBpdWaTCKljJPRimtLMrSZrs,90347
@@ -59,7 +59,7 @@ langroid/cachedb/momento_cachedb.py,sha256=YEOJ62hEcV6iIeMr5aGgRYgWQqFYaej9gEDEc
59
59
  langroid/cachedb/redis_cachedb.py,sha256=7kgnbf4b5CKsCrlL97mHWKvdvlLt8zgn7lc528jEpiE,5141
60
60
  langroid/embedding_models/__init__.py,sha256=KyYxR3jDFUCfYjSuCL86qjAmrq6mXXjOT4lFNOKVj6Y,955
61
61
  langroid/embedding_models/base.py,sha256=Ml7oA6PzQm0wZmIYn3fhF7dvZCi-amviWUwOeBegH3A,2562
62
- langroid/embedding_models/models.py,sha256=fKQBiaaG7uYoeELDbAiNxwLdn-CWN8dyiVEZcdk_bjI,18959
62
+ langroid/embedding_models/models.py,sha256=93rQjvcltGLDYbgT1TIW8PZiAbNPAvPAqxCLlLS9GAo,18955
63
63
  langroid/embedding_models/remote_embeds.py,sha256=6_kjXByVbqhY9cGwl9R83ZcYC2km-nGieNNAo1McHaY,5151
64
64
  langroid/embedding_models/protoc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
65
  langroid/embedding_models/protoc/embeddings.proto,sha256=_O-SgFpTaylQeOTgSpxhEJ7CUw7PeCQQJLaPqpPYKJg,321
@@ -68,11 +68,11 @@ langroid/embedding_models/protoc/embeddings_pb2.pyi,sha256=UkNy7BrNsmQm0vLb3NtGX
68
68
  langroid/embedding_models/protoc/embeddings_pb2_grpc.py,sha256=9dYQqkW3JPyBpSEjeGXTNpSqAkC-6FPtBHyteVob2Y8,2452
69
69
  langroid/language_models/__init__.py,sha256=3aD2qC1lz8v12HX4B-dilv27gNxYdGdeu1QvDlkqqHs,1095
70
70
  langroid/language_models/azure_openai.py,sha256=zNQzzsERxNestq-hFfQZbvTzK43G2vjRWnTV3ktm1DQ,5845
71
- langroid/language_models/base.py,sha256=mN6HAjLgF2xpHObz5uPZ3JDID7jdTiRLEkoGgGrqLM8,25177
71
+ langroid/language_models/base.py,sha256=is4l3x858tdPHbrJU2jxJXe2j9PCGb9kk_c5nyfShxs,26150
72
72
  langroid/language_models/config.py,sha256=9Q8wk5a7RQr8LGMT_0WkpjY8S4ywK06SalVRjXlfCiI,378
73
73
  langroid/language_models/mock_lm.py,sha256=5BgHKDVRWFbUwDT_PFgTZXz9-k8wJSA2e3PZmyDgQ1k,4022
74
74
  langroid/language_models/model_info.py,sha256=yKAaKoCanPoqaoHCzRVNPjg-M9a4S2Vm2AJGnwMeO-M,11360
75
- langroid/language_models/openai_gpt.py,sha256=hC6knKQ9s9-bNixPWduxLRhLxs3y1zyfW7hU8oWWtHQ,78681
75
+ langroid/language_models/openai_gpt.py,sha256=aajZ3ZvGkwI-3QdsNWgJ4QSyGpnyXJ5n4p2fYGUmdo4,77317
76
76
  langroid/language_models/utils.py,sha256=L4_CbihDMTGcsg0TOG1Yd5JFEto46--h7CX_14m89sQ,5016
77
77
  langroid/language_models/prompt_formatter/__init__.py,sha256=2-5cdE24XoFDhifOLl8yiscohil1ogbP1ECkYdBlBsk,372
78
78
  langroid/language_models/prompt_formatter/base.py,sha256=eDS1sgRNZVnoajwV_ZIha6cba5Dt8xjgzdRbPITwx3Q,1221
@@ -111,7 +111,7 @@ langroid/utils/object_registry.py,sha256=iPz9GHzvmCeVoidB3JdAMEKcxJEqTdUr0otQEex
111
111
  langroid/utils/pandas_utils.py,sha256=UctS986Jtl_MvU5rA7-GfrjEHXP7MNu8ePhepv0bTn0,755
112
112
  langroid/utils/pydantic_utils.py,sha256=R7Ps8VP56-eSo-LYHWllFo-SJ2zDmdItuuYpUq2gGJ8,20854
113
113
  langroid/utils/system.py,sha256=cJqDgOf9mM82l1GyUeQQdEYAwepYXQwtpJU8Xrz0-MA,8453
114
- langroid/utils/types.py,sha256=4GrOnU3HLWh-UwaUPp7LlB3V413q3K5OSzc0ggDoQ6A,2510
114
+ langroid/utils/types.py,sha256=-BvyIf_LmAJ5jR9NC7S4CSVNEr3XayAaxJ5o0TiIej0,2992
115
115
  langroid/utils/algorithms/__init__.py,sha256=WylYoZymA0fnzpB4vrsH_0n7WsoLhmuZq8qxsOCjUpM,41
116
116
  langroid/utils/algorithms/graph.py,sha256=JbdpPnUOhw4-D6O7ou101JLA3xPCD0Lr3qaPoFCaRfo,2866
117
117
  langroid/utils/output/__init__.py,sha256=7P0f--4IZneNsTxXY5fd6d6iW-CeVe-KSsl-87sbBPc,340
@@ -128,7 +128,7 @@ langroid/vector_store/pineconedb.py,sha256=otxXZNaBKb9f_H75HTaU3lMHiaR2NUp5MqwLZ
128
128
  langroid/vector_store/postgres.py,sha256=DQHd6dt-OcV_QVNm-ymn28rlTfhI6hqgcpLTPCsm0jI,15990
129
129
  langroid/vector_store/qdrantdb.py,sha256=v7TAsIoj_vxeKDYS9tpwJLBZA8fuTweTYxHo0X_uawM,17949
130
130
  langroid/vector_store/weaviatedb.py,sha256=ONEr2iGS0Ii73oMe7tRk6bB-BEXQUa70fYSrdI8d3yo,11481
131
- langroid-0.41.2.dist-info/METADATA,sha256=FWd7a2bi9c79wldH9KrVvq2U7Jtu_XeEWI9XcF17FpE,61259
132
- langroid-0.41.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
133
- langroid-0.41.2.dist-info/licenses/LICENSE,sha256=EgVbvA6VSYgUlvC3RvPKehSg7MFaxWDsFuzLOsPPfJg,1065
134
- langroid-0.41.2.dist-info/RECORD,,
131
+ langroid-0.41.4.dist-info/METADATA,sha256=hU062qh537keZYiNQZhdKWffOldsn_lz5BWYew1TQbg,61331
132
+ langroid-0.41.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
133
+ langroid-0.41.4.dist-info/licenses/LICENSE,sha256=EgVbvA6VSYgUlvC3RvPKehSg7MFaxWDsFuzLOsPPfJg,1065
134
+ langroid-0.41.4.dist-info/RECORD,,