langroid 0.8.0__py3-none-any.whl → 0.9.1__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.
@@ -32,12 +32,7 @@ class AddRecipientTool(ToolMessage):
32
32
  "to clarify who the message is intended for."
33
33
  )
34
34
  intended_recipient: str
35
- saved_content: str = ""
36
-
37
- class Config:
38
- # do not include these fields in the generated schema
39
- # since we don't require the LLM to specify them
40
- schema_extra = {"exclude": {"saved_content", "purpose"}}
35
+ _saved_content: str = ""
41
36
 
42
37
  def response(self, agent: ChatAgent) -> ChatDocument:
43
38
  """
@@ -49,7 +44,7 @@ class AddRecipientTool(ToolMessage):
49
44
  "[red]RecipientTool: "
50
45
  f"Added recipient {self.intended_recipient} to message."
51
46
  )
52
- if self.__class__.saved_content == "":
47
+ if self.__class__._saved_content == "":
53
48
  recipient_request_name = RecipientTool.default_value("request")
54
49
  content = f"""
55
50
  Recipient specified but content is empty!
@@ -58,9 +53,9 @@ class AddRecipientTool(ToolMessage):
58
53
  Resend the message using `{recipient_request_name}` tool/function.
59
54
  """
60
55
  else:
61
- content = self.__class__.saved_content # use class-level attrib value
56
+ content = self.__class__._saved_content # use class-level attrib value
62
57
  # erase content since we just used it.
63
- self.__class__.saved_content = ""
58
+ self.__class__._saved_content = ""
64
59
  return ChatDocument(
65
60
  content=content,
66
61
  metadata=ChatDocMetaData(
@@ -152,7 +147,7 @@ class RecipientTool(ToolMessage):
152
147
  # save the content as a class-variable, so that
153
148
  # we can construct the ChatDocument once the LLM specifies a recipient.
154
149
  # This avoids having to re-generate the entire message, saving time + cost.
155
- AddRecipientTool.saved_content = self.content
150
+ AddRecipientTool._saved_content = self.content
156
151
  agent.enable_message(AddRecipientTool)
157
152
  return ChatDocument(
158
153
  content="""
@@ -214,7 +209,7 @@ class RecipientTool(ToolMessage):
214
209
  # save the content as a class-variable, so that
215
210
  # we can construct the ChatDocument once the LLM specifies a recipient.
216
211
  # This avoids having to re-generate the entire message, saving time + cost.
217
- AddRecipientTool.saved_content = content
212
+ AddRecipientTool._saved_content = content
218
213
  agent.enable_message(AddRecipientTool)
219
214
  print("[red]RecipientTool: Recipient not specified, asking LLM to clarify.")
220
215
  return ChatDocument(
@@ -0,0 +1,19 @@
1
+ # from langroid.agent.tool_message import ToolMessage
2
+ # from langroid.agent.task import Task
3
+ # from typing import Any
4
+ #
5
+ # class TypedTask:
6
+ # def __init__(self, Task: Task, input_type: Any, output_type: Any):
7
+ # self.Task = Task
8
+ # self.input_type = input_type
9
+ # self.output_type = output_type
10
+ #
11
+ # def run(self, input: Any) -> Any:
12
+ # if not isinstance(input, self.input_type):
13
+ # raise ValueError(f"Input must be of type {self.input_type}")
14
+ # output = self.Task.run(input)
15
+ # if not isinstance(output, self.output_type):
16
+ # raise ValueError(f"Output must be of type {self.output_type}")
17
+ # return output
18
+ #
19
+ #
@@ -294,8 +294,9 @@ class LLMResponse(BaseModel):
294
294
  of the recipient name if specified.
295
295
 
296
296
  Two cases:
297
- (a) `message` contains "TO: <name> <content>", or
298
- (b) `message` is empty and `function_call` with `to: <name>`
297
+ (a) `message` contains addressing string "TO: <name> <content>", or
298
+ (b) `message` is empty and function_call/tool_call with explicit `recipient`
299
+
299
300
 
300
301
  Returns:
301
302
  (str): name of recipient, which may be empty string if no recipient
langroid/mytypes.py CHANGED
@@ -76,7 +76,6 @@ class Document(BaseModel):
76
76
  return self.metadata.id
77
77
 
78
78
  def __str__(self) -> str:
79
- # TODO: make metadata a pydantic model to enforce "source"
80
79
  return dedent(
81
80
  f"""
82
81
  CONTENT: {self.content}
@@ -89,11 +89,28 @@ def parse_imperfect_json(json_string: str) -> Union[Dict[str, Any], List[Any]]:
89
89
 
90
90
  # If ast.literal_eval fails or returns non-dict/list, try json.loads
91
91
  try:
92
- str = add_quotes(json_string)
93
- result = json.loads(str)
92
+ json_string = add_quotes(json_string)
93
+ result = json.loads(json_string)
94
94
  if isinstance(result, (dict, list)):
95
95
  return result
96
96
  except json.JSONDecodeError:
97
+ try:
98
+ # fallback on yaml
99
+ yaml_result = yaml.safe_load(json_string)
100
+ if isinstance(yaml_result, (dict, list)):
101
+ return yaml_result
102
+ except yaml.YAMLError:
103
+ pass
104
+
105
+ try:
106
+ # last resort: try to repair the json using a lib
107
+ from json_repair import repair_json
108
+
109
+ repaired_json = repair_json(json_string)
110
+ result = json.loads(repaired_json)
111
+ if isinstance(result, (dict, list)):
112
+ return result
113
+ except Exception:
97
114
  pass
98
115
 
99
116
  # If all methods fail, raise ValueError
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ from collections.abc import MutableMapping
2
3
  from contextlib import contextmanager
3
4
  from typing import (
4
5
  Any,
@@ -21,6 +22,24 @@ from langroid.pydantic_v1 import BaseModel, ValidationError, create_model
21
22
  logger = logging.getLogger(__name__)
22
23
 
23
24
 
25
+ def flatten_dict(
26
+ d: MutableMapping[str, Any], parent_key: str = "", sep: str = "."
27
+ ) -> Dict[str, Any]:
28
+ """Flatten a nested dictionary, using a separator in the keys.
29
+ Useful for pydantic_v1 models with nested fields -- first use
30
+ dct = mdl.model_dump()
31
+ to get a nested dictionary, then use this function to flatten it.
32
+ """
33
+ items: List[Tuple[str, Any]] = []
34
+ for k, v in d.items():
35
+ new_key = f"{parent_key}{sep}{k}" if parent_key else k
36
+ if isinstance(v, MutableMapping):
37
+ items.extend(flatten_dict(v, new_key, sep=sep).items())
38
+ else:
39
+ items.append((new_key, v))
40
+ return dict(items)
41
+
42
+
24
43
  def has_field(model_class: Type[BaseModel], field_name: str) -> bool:
25
44
  """Check if a Pydantic model class has a field with the given name."""
26
45
  return field_name in model_class.__fields__
@@ -15,6 +15,7 @@ from langroid.utils.configuration import settings
15
15
  from langroid.utils.object_registry import ObjectRegistry
16
16
  from langroid.utils.output.printing import print_long_text
17
17
  from langroid.utils.pandas_utils import stringify
18
+ from langroid.utils.pydantic_utils import flatten_dict
18
19
 
19
20
  logger = logging.getLogger(__name__)
20
21
 
@@ -136,7 +137,8 @@ class VectorStore(ABC):
136
137
  """Compute a result on a set of documents,
137
138
  using a dataframe calc string like `df.groupby('state')['income'].mean()`.
138
139
  """
139
- dicts = [doc.dict() for doc in docs]
140
+ # convert each doc to a dict, using dotted paths for nested fields
141
+ dicts = [flatten_dict(doc.dict(by_alias=True)) for doc in docs]
140
142
  df = pd.DataFrame(dicts)
141
143
 
142
144
  try:
@@ -147,6 +147,8 @@ class LanceDB(VectorStore):
147
147
 
148
148
  def _create_lance_schema(self, doc_cls: Type[Document]) -> Type[BaseModel]:
149
149
  """
150
+ NOTE: NOT USED, but leaving it here as it may be useful.
151
+
150
152
  Create a subclass of LanceModel with fields:
151
153
  - id (str)
152
154
  - Vector field that has dims equal to
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langroid
3
- Version: 0.8.0
3
+ Version: 0.9.1
4
4
  Summary: Harness LLMs with Multi-Agent Programming
5
5
  License: MIT
6
6
  Author: Prasad Chalasani
@@ -54,6 +54,7 @@ Requires-Dist: grpcio (>=1.62.1,<2.0.0)
54
54
  Requires-Dist: halo (>=0.0.31,<0.0.32)
55
55
  Requires-Dist: huggingface-hub (>=0.21.2,<0.22.0) ; extra == "hf-transformers" or extra == "all" or extra == "transformers"
56
56
  Requires-Dist: jinja2 (>=3.1.2,<4.0.0)
57
+ Requires-Dist: json-repair (>=0.27.0,<0.28.0)
57
58
  Requires-Dist: lancedb (>=0.8.2,<0.9.0) ; extra == "vecdbs" or extra == "lancedb"
58
59
  Requires-Dist: litellm (>=1.30.1,<2.0.0) ; extra == "all" or extra == "litellm"
59
60
  Requires-Dist: lxml (>=4.9.3,<5.0.0)
@@ -236,7 +237,8 @@ teacher_task.run()
236
237
  <summary> <b>Click to expand</b></summary>
237
238
 
238
239
  - **Aug 2024:**
239
- - **[0.7.0](https://github.com/langroid/langroid/releases/tag/0.7.0)** OpenAI tools API support.
240
+ - **[0.9.0](https://github.com/langroid/langroid/releases/tag/0.9.0)** Orchestration Tools, to signal various task statuses, and to pass messages between agents.
241
+ - **[0.7.0](https://github.com/langroid/langroid/releases/tag/0.7.0)** OpenAI tools API support, including multi-tools.
240
242
  - **Jul 2024:**
241
243
  - **[0.3.0](https://github.com/langroid/langroid/releases/tag/0.3.0)**: Added [FastEmbed](https://qdrant.github.io/fastembed/qdrant/Usage_With_Qdrant/) embeddings from Qdrant
242
244
  - **Jun 2024:**
@@ -1,26 +1,22 @@
1
1
  langroid/__init__.py,sha256=z_fCOLQJPOw3LLRPBlFB5-2HyCjpPgQa4m4iY5Fvb8Y,1800
2
2
  langroid/agent/__init__.py,sha256=ll0Cubd2DZ-fsCMl7e10hf9ZjFGKzphfBco396IKITY,786
3
- langroid/agent/base.py,sha256=EOAdZ2K0Yjjdt3zkjNsUhHgRvYZT-eIgRbY4ldjt6hY,46995
3
+ langroid/agent/base.py,sha256=dCGYbT2s35OEgbYtuDWOBhpeJzjo2TPnbbG4NrjVv70,58201
4
4
  langroid/agent/batch.py,sha256=feRA_yRG768ElOQjrKEefcRv6Aefd_yY7qktuYUQDwc,10040
5
5
  langroid/agent/callbacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  langroid/agent/callbacks/chainlit.py,sha256=Qedk1-CBCgo9PdaIa7AboLBFCTgAMg9q5nGmoqpZ378,22050
7
- langroid/agent/chat_agent.py,sha256=4bgLHBFSxL1dw1UAEF5zfCqnp_ss0MUUTOnjKkfOJRQ,45401
8
- langroid/agent/chat_document.py,sha256=y3QBdpclTBuqs42c3lLO9HU4s70PyK133HXZxyaxNZ8,16322
7
+ langroid/agent/chat_agent.py,sha256=VUuYweOLuH4lokvZLY74WXIG4AlxRU4L907ox_hoRA4,48107
8
+ langroid/agent/chat_document.py,sha256=Cq-TbPefpxbx2QzGl-CUpIrCcEC34GHDGH6Fd0w7aYs,16693
9
9
  langroid/agent/helpers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  langroid/agent/junk,sha256=LxfuuW7Cijsg0szAzT81OjWWv1PMNI-6w_-DspVIO2s,339
11
- langroid/agent/openai_assistant.py,sha256=TlMi5QecrxxhZ7TW03wB161elSSQYwL7H0xk8g7HawU,33879
11
+ langroid/agent/openai_assistant.py,sha256=2rjCZw45ysNBEGNzQM4uf0bTC4KkatGYAWcVcW4xcek,34337
12
12
  langroid/agent/special/__init__.py,sha256=gik_Xtm_zV7U9s30Mn8UX3Gyuy4jTjQe9zjiE3HWmEo,1273
13
13
  langroid/agent/special/doc_chat_agent.py,sha256=8NPAhMnHkFUolQ8EHos40tz5Vwuz_m33NjUfjheXWXY,54569
14
- langroid/agent/special/lance_doc_chat_agent.py,sha256=Hjpu6u9UPAFMg5J6K97PRFaLbNrGhInC0N9oGi09CeY,10006
14
+ langroid/agent/special/lance_doc_chat_agent.py,sha256=s8xoRs0gGaFtDYFUSIRchsgDVbS5Q3C2b2mr3V1Fd-Q,10419
15
15
  langroid/agent/special/lance_rag/__init__.py,sha256=QTbs0IVE2ZgDg8JJy1zN97rUUg4uEPH7SLGctFNumk4,174
16
- langroid/agent/special/lance_rag/critic_agent.py,sha256=S3NA3OAO7XaXjCrmwhKB7qCPlgRZFvDxiB5Qra65Zhs,7959
16
+ langroid/agent/special/lance_rag/critic_agent.py,sha256=lRHLBU9TWo4ixm_wEPUP9bCjW0iSIw7ZRe6u4D4v7jk,9519
17
17
  langroid/agent/special/lance_rag/lance_rag_task.py,sha256=l_HQgrYY-CX2FwIsS961aEF3bYog3GDYo98fj0C0mSk,2889
18
- langroid/agent/special/lance_rag/query_planner_agent.py,sha256=QB8UYITUCkgSPturEwu_3i4kU8jXxW_jXNGSLlH5tMc,10109
19
- langroid/agent/special/lance_rag_new/__init__.py,sha256=QTbs0IVE2ZgDg8JJy1zN97rUUg4uEPH7SLGctFNumk4,174
20
- langroid/agent/special/lance_rag_new/critic_agent.py,sha256=9TV0_ILQ1jNeO9Pjeirz3VsUsCKeImyVHPu-fJub6cY,8340
21
- langroid/agent/special/lance_rag_new/lance_rag_task.py,sha256=mKo4lCC1ff5Jt9BlxwclQ_y3omw2S_f0MVIJfNmXM6w,5267
22
- langroid/agent/special/lance_rag_new/query_planner_agent.py,sha256=JqO_5fKW8HPn-zqKsZzX1sl05RgtcT63qpDMR9-q33A,10251
23
- langroid/agent/special/lance_tools.py,sha256=BznV_r3LAFyybvBRa9KQ0oU7mPM3uQVfri7PFp7M_qc,1894
18
+ langroid/agent/special/lance_rag/query_planner_agent.py,sha256=-ZKareApPQD0EbwB1ABeZdhYAA2lJbwSVkfSuhMcKMk,11480
19
+ langroid/agent/special/lance_tools.py,sha256=qS8x4wi8mrqfbYV2ztFzrcxyhHQ0ZWOc-zkYiH7awj0,2105
24
20
  langroid/agent/special/neo4j/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
21
  langroid/agent/special/neo4j/csv_kg_chat.py,sha256=dRsAgMBa1H_EMI2YYgJR2Xyv1D7e4o3G9M64mTewq_c,6409
26
22
  langroid/agent/special/neo4j/neo4j_chat_agent.py,sha256=dvZ4rrMWwKuOIOjC3iWQIe-cSxNXkaU_6W0rQII_4Q8,13347
@@ -36,21 +32,22 @@ langroid/agent/special/sql/utils/populate_metadata.py,sha256=1J22UsyEPKzwK0XlJZt
36
32
  langroid/agent/special/sql/utils/system_message.py,sha256=qKLHkvQWRQodTtPLPxr1GSLUYUFASZU8x-ybV67cB68,1885
37
33
  langroid/agent/special/sql/utils/tools.py,sha256=vFYysk6Vi7HJjII8B4RitA3pt_z3gkSglDNdhNVMiFc,1332
38
34
  langroid/agent/special/table_chat_agent.py,sha256=d9v2wsblaRx7oMnKhLV7uO_ujvk9gh59pSGvBXyeyNc,9659
39
- langroid/agent/task.py,sha256=eCA91yr6DSaRRGteTbSki-liMl6nspzRd_5Gin_ZFYw,75176
40
- langroid/agent/team.py,sha256=88VNRSmK35WEl620GfBzuIrBASXYSeBZ8yDKX-nP_Bo,75778
41
- langroid/agent/tool_message.py,sha256=XPM6whazpUOQu_vM2D4Q_L9tV6Vs9OTXNrGchwcqD_o,9768
42
- langroid/agent/tools/__init__.py,sha256=e-63cfwQNk_ftRKQwgDAJQK16QLbRVWDBILeXIc7wLk,402
35
+ langroid/agent/task.py,sha256=taSP80E_pcqa6OEGi9weOQXx7It8SZvgosfuVv4DQcw,80300
36
+ langroid/agent/tool_message.py,sha256=pArap87HNODwBVH2Dyu4Oi_OOhK0NH65pDUOHvIKV0E,10101
37
+ langroid/agent/tools/__init__.py,sha256=lgWAWsPgMx-NdDPVX6tXO_U0cIQX7dwzhUC0G4IfUgk,726
43
38
  langroid/agent/tools/duckduckgo_search_tool.py,sha256=NhsCaGZkdv28nja7yveAhSK_w6l_Ftym8agbrdzqgfo,1935
44
39
  langroid/agent/tools/extract_tool.py,sha256=u5lL9rKBzaLBOrRyLnTAZ97pQ1uxyLP39XsWMnpaZpw,3789
45
40
  langroid/agent/tools/generator_tool.py,sha256=y0fB0ZObjA0b3L0uSTtrqRCKHDUR95arBftqiUeKD2o,663
46
41
  langroid/agent/tools/google_search_tool.py,sha256=y7b-3FtgXf0lfF4AYxrZ3K5pH2dhidvibUOAGBE--WI,1456
47
42
  langroid/agent/tools/metaphor_search_tool.py,sha256=qj4gt453cLEX3EGW7nVzVu6X7LCdrwjSlcNY0qJW104,2489
48
43
  langroid/agent/tools/note_tool.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
- langroid/agent/tools/recipient_tool.py,sha256=NrLxIeQT-kbMv7AeYX0uqvGeMK4Q3fIDvG15OVzlgk8,9624
44
+ langroid/agent/tools/orchestration.py,sha256=MN-y5erSiCnsPtI7aeD7rn5K3kXzeQnJHRlCkenkloY,7324
45
+ langroid/agent/tools/recipient_tool.py,sha256=0m2kQhYKTeGujAxhSPqH5z6hSAhVB_Dqour6uul2U30,9427
50
46
  langroid/agent/tools/retrieval_tool.py,sha256=2q2pfoYbZNfbWQ0McxrtmfF0ekGglIgRl-6uF26pa-E,871
51
47
  langroid/agent/tools/rewind_tool.py,sha256=XAXL3BpNhCmBGYq_qi_sZfHJuIw7NY2jp4wnojJ7WRs,5606
52
48
  langroid/agent/tools/run_python_code.py,sha256=BvoxYzzHijU-p4703n2iVlt5BCieR1oMSy50w0tQZAg,1787
53
49
  langroid/agent/tools/segment_extract_tool.py,sha256=__srZ_VGYLVOdPrITUM8S0HpmX4q7r5FHWMDdHdEv8w,1440
50
+ langroid/agent/typed_task.py,sha256=oxja0Z3uLTv0BcR1xIMqDpo85MIGOruz4XsZ4ghjsW4,689
54
51
  langroid/agent_config.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
52
  langroid/cachedb/__init__.py,sha256=icAT2s7Vhf-ZGUeqpDQGNU6ob6o0aFEyjwcxxUGRFjg,225
56
53
  langroid/cachedb/base.py,sha256=ztVjB1DtN6pLCujCWnR6xruHxwVj3XkYniRTYAKKqk0,1354
@@ -71,7 +68,7 @@ langroid/language_models/.chainlit/config.toml,sha256=1t5lHORGzc2E6dkaO9P15jYHu2
71
68
  langroid/language_models/.chainlit/translations/en-US.json,sha256=DAFz2HjOFFfboCStrUfKFg2BpplJPK_OOtixwF_GivY,9931
72
69
  langroid/language_models/__init__.py,sha256=1sUGobooTqq77XC7LxKsvME0RgSd5GGmeyrPo9SMh4U,940
73
70
  langroid/language_models/azure_openai.py,sha256=G4le3j4YLHV7IwgB2C37hO3MKijZ1KjynbYlEvpIF7Y,6214
74
- langroid/language_models/base.py,sha256=L76syCytos5IaQ5tpgToYJHThch4gA9uyjeMmjWjZ8E,21757
71
+ langroid/language_models/base.py,sha256=ytJ_0Jw5erbqrqLPp4JMCo_nIkwzUvBqoKUr8Sae9Qg,21792
75
72
  langroid/language_models/config.py,sha256=9Q8wk5a7RQr8LGMT_0WkpjY8S4ywK06SalVRjXlfCiI,378
76
73
  langroid/language_models/mock_lm.py,sha256=2Ka05SVGSUy096bsa2AyjaqC5jmcFoe7HycpdnICTIw,3031
77
74
  langroid/language_models/openai_gpt.py,sha256=Bv-FCva9q0oO85VSqNpaxEYI8zPwVXpHmmfV7O8QRhU,61325
@@ -80,7 +77,7 @@ langroid/language_models/prompt_formatter/base.py,sha256=eDS1sgRNZVnoajwV_ZIha6c
80
77
  langroid/language_models/prompt_formatter/hf_formatter.py,sha256=TFL6ppmeQWnzr6CKQzRZFYY810zE1mr8DZnhw6i85ok,5217
81
78
  langroid/language_models/prompt_formatter/llama2_formatter.py,sha256=YdcO88qyBeuMENVIVvVqSYuEpvYSTndUe_jd6hVTko4,2899
82
79
  langroid/language_models/utils.py,sha256=o6Zo2cnnvKrfSgF26knVQ1xkSxEoE7yN85296gNdVOw,4858
83
- langroid/mytypes.py,sha256=KRN_dBamplSl3SYekosT_Maj6ZA749LONypaqPVnmbI,2435
80
+ langroid/mytypes.py,sha256=ptAFxEAtiwmIfUnGisNotTe8wT9LKBf22lOfPgZoQIY,2368
84
81
  langroid/parsing/__init__.py,sha256=ZgSAfgTC6VsTLFlRSWT-TwYco7SQeRMeZG-49MnKYGY,936
85
82
  langroid/parsing/agent_chats.py,sha256=sbZRV9ujdM5QXvvuHVjIi2ysYSYlap-uqfMMUKulrW0,1068
86
83
  langroid/parsing/code-parsing.md,sha256=--cyyNiSZSDlIwcjAV4-shKrSiRe2ytF3AdSoS_hD2g,3294
@@ -89,7 +86,7 @@ langroid/parsing/config.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
86
  langroid/parsing/document_parser.py,sha256=WGnA5ADwMHliGJt6WW9rc4RiFXQcKU33b5zdPiGrtEY,24265
90
87
  langroid/parsing/image_text.py,sha256=sbLIQ5nHe2UnYUksBaQsmZGaX-X0qgEpPd7CEzi_z5M,910
91
88
  langroid/parsing/para_sentence_split.py,sha256=AJBzZojP3zpB-_IMiiHismhqcvkrVBQ3ZINoQyx_bE4,2000
92
- langroid/parsing/parse_json.py,sha256=Ivh6YcEOESAi9y8E55E7qhFqfncvnluyb6sZGWK0--U,5268
89
+ langroid/parsing/parse_json.py,sha256=sKrYv9-IUqRFaTJA24_rmfjN1E7dQSrTBrtd1jYDE1s,5817
93
90
  langroid/parsing/parser.py,sha256=AgtmlVUvrkSG1l7-YZPX8rlldgXjh_HqXAMqpXkBxUo,11746
94
91
  langroid/parsing/repo_loader.py,sha256=3GjvPJS6Vf5L6gV2zOU8s-Tf1oq_fZm-IB_RL_7CTsY,29373
95
92
  langroid/parsing/routing.py,sha256=-FcnlqldzL4ZoxuDwXjQPNHgBe9F9-F4R6q7b_z9CvI,1232
@@ -124,20 +121,20 @@ langroid/utils/output/citations.py,sha256=PSY2cpti8W-ZGFMAgj1lYoEIZy0lsniLpCliMs
124
121
  langroid/utils/output/printing.py,sha256=yzPJZN-8_jyOJmI9N_oLwEDfjMwVgk3IDiwnZ4eK_AE,2962
125
122
  langroid/utils/output/status.py,sha256=rzbE7mDJcgNNvdtylCseQcPGCGghtJvVq3lB-OPJ49E,1049
126
123
  langroid/utils/pandas_utils.py,sha256=UctS986Jtl_MvU5rA7-GfrjEHXP7MNu8ePhepv0bTn0,755
127
- langroid/utils/pydantic_utils.py,sha256=X35qxjE4sSIi-oBMkI1s9fiUIJbpXHLmJqcJ7zsy0jg,19914
124
+ langroid/utils/pydantic_utils.py,sha256=iRy7uQhHhQmIDZTTPNX5jXb6fqefMe9N67p3fPfOmTI,20624
128
125
  langroid/utils/system.py,sha256=nvKeeUAj4eviR4kYpcr9h-HYdhqUNMTRBTHBOhz0GdU,5182
129
126
  langroid/utils/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
127
  langroid/utils/web/login.py,sha256=1iz9eUAHa87vpKIkzwkmFa00avwFWivDSAr7QUhK7U0,2528
131
128
  langroid/vector_store/__init__.py,sha256=6xBjb_z4QtUy4vz4RuFbcbSwmHrggHL8-q0DwCf3PMM,972
132
- langroid/vector_store/base.py,sha256=pkc4n0yWGVk7iRUOLFkU_ID5NiBFfAcA3lBlPNX79pU,13623
129
+ langroid/vector_store/base.py,sha256=BDsGl9D8TeepZK8-8SSIxpx9LJRJF9ic_xw4WjBX3sI,13780
133
130
  langroid/vector_store/chromadb.py,sha256=KMfHrgovQEOeJR_LsMpGM8BteJ50wpisDu608RhU3SU,7940
134
- langroid/vector_store/lancedb.py,sha256=MLubJBhtNIFX6zY0qANqCoB6MlL-oZiJCg9gZp2H2rs,14620
131
+ langroid/vector_store/lancedb.py,sha256=kWIQ9QxFKS8gJ7cSn11empvi7Q6_NvXNkc4f-CmVZMg,14686
135
132
  langroid/vector_store/meilisearch.py,sha256=6frB7GFWeWmeKzRfLZIvzRjllniZ1cYj3HmhHQICXLs,11663
136
133
  langroid/vector_store/momento.py,sha256=qR-zBF1RKVHQZPZQYW_7g-XpTwr46p8HJuYPCkfJbM4,10534
137
134
  langroid/vector_store/qdrant_cloud.py,sha256=3im4Mip0QXLkR6wiqVsjV1QvhSElfxdFSuDKddBDQ-4,188
138
135
  langroid/vector_store/qdrantdb.py,sha256=v88lqFkepADvlN6lByUj9I4NEKa9X9lWH16uTPPbYrE,17457
139
- pyproject.toml,sha256=pK1C4vWrb5-NkREBDkFao-3Pi-xXJXMjh_wjedpjFAk,7063
140
- langroid-0.8.0.dist-info/LICENSE,sha256=EgVbvA6VSYgUlvC3RvPKehSg7MFaxWDsFuzLOsPPfJg,1065
141
- langroid-0.8.0.dist-info/METADATA,sha256=i2_aKdjkgYcGAYMXEG2F3NC59yVI1w3uidn3edm5wAY,54518
142
- langroid-0.8.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
143
- langroid-0.8.0.dist-info/RECORD,,
136
+ pyproject.toml,sha256=vMlwc5WYI8gotrY4XvY5I-pRI4LPiUYU2KsaqEZxfvQ,7087
137
+ langroid-0.9.1.dist-info/LICENSE,sha256=EgVbvA6VSYgUlvC3RvPKehSg7MFaxWDsFuzLOsPPfJg,1065
138
+ langroid-0.9.1.dist-info/METADATA,sha256=z_Dkfgzr-BDwsHnehLrejgyFJPYkdMHPwb7GFHcobj4,54751
139
+ langroid-0.9.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
140
+ langroid-0.9.1.dist-info/RECORD,,
pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "langroid"
3
- version = "0.8.0"
3
+ version = "0.9.1"
4
4
  description = "Harness LLMs with Multi-Agent Programming"
5
5
  authors = ["Prasad Chalasani <pchalasani@gmail.com>"]
6
6
  readme = "README.md"
@@ -88,6 +88,7 @@ nest-asyncio = "^1.6.0"
88
88
  async-generator = "^1.10"
89
89
 
90
90
  python-magic = "^0.4.27"
91
+ json-repair = "^0.27.0"
91
92
 
92
93
  [tool.poetry.extras]
93
94
  # install these using, e.g.,
@@ -1,9 +0,0 @@
1
- from . import query_planner_agent
2
- from . import critic_agent
3
- from . import lance_rag_task
4
-
5
- __all__ = [
6
- "query_planner_agent",
7
- "critic_agent",
8
- "lance_rag_task",
9
- ]
@@ -1,171 +0,0 @@
1
- """
2
- QueryPlanCritic is a ChatAgent that is created with a specific document schema.
3
-
4
- Its role is to provide feedback on a Query Plan, which consists of:
5
- - filter condition if needed (or empty string if no filter is needed)
6
- - query - a possibly rephrased query that can be used to match the `content` field
7
- - dataframe_calc - a Pandas-dataframe calculation/aggregation string, possibly empty
8
- - original_query - the original query for reference
9
- - result - the answer received from an assistant that used this QUERY PLAN.
10
-
11
- This agent has access to two tools:
12
- - QueryPlanTool: The handler method for this tool re-writes the query plan
13
- in plain text (non-JSON) so the LLM can provide its feedback using the
14
- QueryPlanFeedbackTool.
15
- - QueryPlanFeedbackTool: LLM uses this tool to provide feedback on the Query Plan
16
- """
17
-
18
- import logging
19
-
20
- from langroid.agent.chat_agent import ChatAgent
21
- from langroid.agent.chat_document import ChatDocument
22
- from langroid.agent.special.lance_rag.query_planner_agent import (
23
- LanceQueryPlanAgentConfig,
24
- )
25
- from langroid.agent.special.lance_tools import (
26
- QueryPlanAnswerTool,
27
- QueryPlanFeedbackTool,
28
- )
29
- from langroid.mytypes import Entity
30
- from langroid.utils.constants import DONE, NO_ANSWER
31
-
32
- logger = logging.getLogger(__name__)
33
-
34
-
35
- class QueryPlanCriticConfig(LanceQueryPlanAgentConfig):
36
- name = "QueryPlanCritic"
37
- system_message = f"""
38
- You are an expert at carefully planning a query that needs to be answered
39
- based on a large collection of documents. These docs have a special `content` field
40
- and additional FILTERABLE fields in the SCHEMA below, along with the
41
- SAMPLE VALUES for each field, and the DTYPE in PANDAS TERMINOLOGY.
42
-
43
- {{doc_schema}}
44
-
45
- The ORIGINAL QUERY is handled by a QUERY PLANNER who sends the PLAN to an ASSISTANT,
46
- who returns an ANSWER.
47
-
48
- You will receive a QUERY PLAN consisting of:
49
- - ORIGINAL QUERY from the user, which a QUERY PLANNER processes,
50
- to create a QUERY PLAN, to be handled by an ASSISTANT.
51
- - PANDAS-LIKE FILTER, WHICH CAN BE EMPTY (and it's fine if results sound reasonable)
52
- FILTER SHOULD ONLY BE USED IF EXPLICITLY REQUIRED BY THE QUERY.
53
- - REPHRASED QUERY (CANNOT BE EMPTY) that will be used to match against the
54
- CONTENT (not filterable) of the documents.
55
- In general the REPHRASED QUERY should be relied upon to match the CONTENT
56
- of the docs. Thus the REPHRASED QUERY itself acts like a
57
- SEMANTIC/LEXICAL/FUZZY FILTER since the Assistant is able to use it to match
58
- the CONTENT of the docs in various ways (semantic, lexical, fuzzy, etc.).
59
- Keep in mind that the ASSISTANT does NOT know anything about the FILTER fields,
60
- so the REPHRASED QUERY should NOT mention ANY FILTER fields.
61
- The assistant will answer based on documents whose CONTENTS match the QUERY,
62
- possibly REPHRASED.
63
- !!!!****THE REPHRASED QUERY SHOULD NEVER BE EMPTY****!!!
64
- - DATAFRAME CALCULATION, which must be a SINGLE LINE calculation (or empty),
65
- [NOTE ==> This calculation is applied AFTER the FILTER and REPHRASED QUERY.],
66
- - ANSWER received from an assistant that used this QUERY PLAN.
67
- NOTE --the ANSWER will usually NOT contain any references to FILTERING conditions,
68
- and this is ALLOWED, since the ANSWER is based on documents AFTER FILTERING.
69
-
70
- In addition to the above SCHEMA fields there is a `content` field which:
71
- - CANNOT appear in a FILTER,
72
- - CAN appear in the DATAFRAME CALCULATION.
73
- THERE ARE NO OTHER FIELDS IN THE DOCUMENTS or in the RESULTING DATAFRAME.
74
-
75
- Your job is to act as a CRITIC and provide feedback,
76
- ONLY using the `query_plan_feedback` tool, and DO NOT SAY ANYTHING ELSE.
77
-
78
- Here is how you must examine the QUERY PLAN + ANSWER:
79
- - ALL filtering conditions in the original query must be EXPLICITLY
80
- mentioned in the FILTER, and the QUERY field should not be used for filtering.
81
- - If the ANSWER contains an ERROR message, then this means that the query
82
- plan execution FAILED, and your feedback should say INVALID along
83
- with the ERROR message, `suggested_fix` that aims to help the assistant
84
- fix the problem (or simply equals "address the the error shown in feedback")
85
- - Ask yourself, is the ANSWER in the expected form, e.g.
86
- if the question is asking for the name of an ENTITY with max SIZE,
87
- then the answer should be the ENTITY name, NOT the SIZE!!
88
- - It is perfectly FINE if the ANSWER does NOT contain any references to FILTERING
89
- conditions, since the ANSWER is obtained from documents AFTER FILTERING!
90
- - If the ANSWER is in the expected form, then the QUERY PLAN is likely VALID,
91
- and your feedback should say VALID, with empty `suggested_fix`.
92
- ===> HOWEVER!!! Watch out for a spurious correct-looking answer, for EXAMPLE:
93
- the query was to find the ENTITY with a maximum SIZE,
94
- but the dataframe calculation is find the SIZE, NOT the ENTITY!!
95
- - If the ANSWER is {NO_ANSWER} or of the wrong form,
96
- then try to DIAGNOSE the problem IN THE FOLLOWING ORDER:
97
- - DATAFRAME CALCULATION -- is it doing the right thing?
98
- Is it finding the Index of a row instead of the value in a column?
99
- Or another example: maybe it is finding the maximum population
100
- rather than the CITY with the maximum population?
101
- If you notice a problem with the DATAFRAME CALCULATION, then
102
- ONLY SUBMIT FEEDBACK ON THE DATAFRAME CALCULATION, and DO NOT
103
- SUGGEST ANYTHING ELSE.
104
- - If the DATAFRAME CALCULATION looks correct, then check if
105
- the REPHRASED QUERY makes sense given the ORIGINAL QUERY and FILTER.
106
- If this is the problem, then ONLY SUBMIT FEEDBACK ON THE REPHRASED QUERY,
107
- and DO NOT SUGGEST ANYTHING ELSE.
108
- - If the REPHRASED QUERY looks correct, then check if the FILTER makes sense.
109
- REMEMBER: A filter should ONLY be used if EXPLICITLY REQUIRED BY THE QUERY.
110
-
111
-
112
- IMPORTANT!! The DATAFRAME CALCULATION is done AFTER applying the
113
- FILTER and REPHRASED QUERY! Keep this in mind when evaluating
114
- the correctness of the DATAFRAME CALCULATION.
115
-
116
- ALWAYS use `query_plan_feedback` tool/fn to present your feedback
117
- in the `feedback` field, and if any fix is suggested,
118
- present it in the `suggested_fix` field.
119
- DO NOT SAY ANYTHING ELSE OUTSIDE THE TOOL/FN.
120
- IF NO REVISION NEEDED, simply leave the `suggested_fix` field EMPTY,
121
- and SAY NOTHING ELSE
122
- and DO NOT EXPLAIN YOURSELF.
123
- """
124
-
125
-
126
- def plain_text_query_plan(msg: QueryPlanAnswerTool) -> str:
127
- plan = f"""
128
- OriginalQuery: {msg.plan.original_query}
129
- Filter: {msg.plan.filter}
130
- Rephrased Query: {msg.plan.query}
131
- DataframeCalc: {msg.plan.dataframe_calc}
132
- Answer: {msg.answer}
133
- """
134
- return plan
135
-
136
-
137
- class QueryPlanCritic(ChatAgent):
138
- """
139
- Critic for LanceQueryPlanAgent, provides feedback on
140
- query plan + answer.
141
- """
142
-
143
- def __init__(self, cfg: LanceQueryPlanAgentConfig):
144
- super().__init__(cfg)
145
- self.config = cfg
146
- self.enable_message(QueryPlanAnswerTool, use=False, handle=True)
147
- self.enable_message(QueryPlanFeedbackTool, use=True, handle=True)
148
-
149
- def query_plan_answer(self, msg: QueryPlanAnswerTool) -> str:
150
- """Present query plan + answer in plain text (not JSON)
151
- so LLM can give feedback"""
152
- return plain_text_query_plan(msg)
153
-
154
- def query_plan_feedback(self, msg: QueryPlanFeedbackTool) -> ChatDocument:
155
- """Format Valid so return to Query Planner"""
156
- doc = self.create_agent_response(DONE)
157
- doc.tool_messages = [msg]
158
- return doc
159
-
160
- def handle_message_fallback(
161
- self, msg: str | ChatDocument
162
- ) -> str | ChatDocument | None:
163
- """Remind the LLM to use QueryPlanFeedbackTool since it forgot"""
164
- if isinstance(msg, ChatDocument) and msg.metadata.sender == Entity.LLM:
165
- return """
166
- You forgot to use the `query_plan_feedback` tool/function.
167
- Re-try your response using the `query_plan_feedback` tool/function,
168
- remember to provide feedback in the `feedback` field,
169
- and if any fix is suggested, provide it in the `suggested_fix` field.
170
- """
171
- return None