langroid 0.1.243__py3-none-any.whl → 0.1.245__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
@@ -812,12 +812,14 @@ class Agent(ABC):
812
812
  llm_model = (
813
813
  "no-LLM" if self.config.llm is None else self.llm.config.chat_model
814
814
  )
815
-
815
+ # tot cost across all LLMs, agents
816
+ all_cost = format(self.llm.tot_tokens_cost()[1], ".4f")
816
817
  return (
817
818
  f"[bold]Stats:[/bold] [magenta]N_MSG={chat_length}, "
818
819
  f"TOKENS: in={in_tokens}, out={out_tokens}, "
819
820
  f"max={max_out}, ctx={context_length}, "
820
- f"COST: now=${llm_response_cost}, cumul=${cumul_cost} "
821
+ f"COST: now=${llm_response_cost}, cumul=${cumul_cost}, "
822
+ f"tot=${all_cost} "
821
823
  f"[bold]({llm_model})[/bold][/magenta]"
822
824
  )
823
825
  return ""
@@ -166,6 +166,16 @@ class ChatDocument(Document):
166
166
  message = message.strip()
167
167
  if message in ["''", '""']:
168
168
  message = ""
169
+ if response.function_call is not None:
170
+ # Sometimes an OpenAI LLM may generate a function-call
171
+ # where the `name` is set, as well as `arugments.request` is set.
172
+ # In this case we override the `name` with the `request` value.
173
+ fc = response.function_call
174
+ if fc.arguments is not None:
175
+ request = fc.arguments.get("request")
176
+ if request is not None and request != "":
177
+ fc.name = request
178
+ fc.arguments.pop("request")
169
179
  return ChatDocument(
170
180
  content=message,
171
181
  function_call=response.function_call,
@@ -52,7 +52,7 @@ class QueryPlanCriticConfig(LanceQueryPlanAgentConfig):
52
52
  SEMANTIC/LEXICAL/FUZZY FILTER since the Assistant is able to use it to match
53
53
  the CONTENT of the docs in various ways (semantic, lexical, fuzzy, etc.).
54
54
 
55
- - DATAFRAME CALCULATION, and
55
+ - DATAFRAME CALCULATION, which must be a SINGLE LINE calculation, and
56
56
  - ANSWER recieved from an assistant that used this QUERY PLAN.
57
57
 
58
58
  In addition to the above SCHEMA fields there is a `content` field which:
@@ -64,8 +64,14 @@ class QueryPlanCriticConfig(LanceQueryPlanAgentConfig):
64
64
  ONLY using the `query_plan_feedback` tool, and DO NOT SAY ANYTHING ELSE.
65
65
 
66
66
  Here is how you must examine the QUERY PLAN + ANSWER:
67
+ - ALL filtering conditions in the original query must be EXPLICITLY
68
+ mentioned in the FILTER, and the QUERY field should not be used for filtering.
69
+ - If the ANSWER contains an ERROR message, then this means that the query
70
+ plan execution FAILED, and your feedback should say INVALID along
71
+ with the ERROR message, `suggested_fix` that aims to help the assistant
72
+ fix the problem (or simply equals "address the the error shown in feedback")
67
73
  - If the ANSWER is in the expected form, then the QUERY PLAN is likely VALID,
68
- and your feedback should be EMPTY.
74
+ and your feedback should say VALID, with empty `suggested_fix`.
69
75
  - If the ANSWER is {NO_ANSWER} or of the wrong form,
70
76
  then try to DIAGNOSE the problem IN THE FOLLOWING ORDER:
71
77
  - DATAFRAME CALCULATION -- is it doing the right thing?
@@ -83,11 +89,13 @@ class QueryPlanCriticConfig(LanceQueryPlanAgentConfig):
83
89
  REMEMBER: A filter should ONLY be used if EXPLICITLY REQUIRED BY THE QUERY.
84
90
 
85
91
 
86
- ALWAYS use `query_plan_feedback` tool/fn to present your feedback!
87
- and DO NOT SAY ANYTHING ELSE OUTSIDE THE TOOL/FN.
88
- IF NO REVISION NEEDED, simply give EMPTY FEEBACK, SAY NOTHING ELSE
89
- and DO NOT EXPLAIN YOURSELF.
90
-
92
+ ALWAYS use `query_plan_feedback` tool/fn to present your feedback
93
+ in the `feedback` field, and if any fix is suggested,
94
+ present it in the `suggested_fix` field.
95
+ DO NOT SAY ANYTHING ELSE OUTSIDE THE TOOL/FN.
96
+ IF NO REVISION NEEDED, simply leave the `suggested_fix` field EMPTY,
97
+ and SAY NOTHING ELSE
98
+ and DO NOT EXPLAIN YOURSELF.
91
99
  """
92
100
 
93
101
 
@@ -95,7 +103,7 @@ def plain_text_query_plan(msg: QueryPlanAnswerTool) -> str:
95
103
  plan = f"""
96
104
  OriginalQuery: {msg.plan.original_query}
97
105
  Filter: {msg.plan.filter}
98
- Query: {msg.plan.query}
106
+ Rephrased Query: {msg.plan.query}
99
107
  DataframeCalc: {msg.plan.dataframe_calc}
100
108
  Answer: {msg.answer}
101
109
  """
@@ -126,11 +134,12 @@ class QueryPlanCritic(ChatAgent):
126
134
  def handle_message_fallback(
127
135
  self, msg: str | ChatDocument
128
136
  ) -> str | ChatDocument | None:
129
- """Create QueryPlanFeedbackTool since LLM forgot"""
137
+ """Remind the LLM to use QueryPlanFeedbackTool since it forgot"""
130
138
  if isinstance(msg, ChatDocument) and msg.metadata.sender == Entity.LLM:
131
- # our LLM forgot to use the QueryPlanFeedbackTool
132
- feedback = QueryPlanFeedbackTool(feedback=msg.content)
133
- msg.tool_messages = [feedback]
134
- msg.content = DONE
135
- return msg
139
+ return """
140
+ You forgot to use the `query_plan_feedback` tool/function.
141
+ Re-try your response using the `query_plan_feedback` tool/function,
142
+ remember to provide feedback in the `feedback` field,
143
+ and if any fix is suggested, provide it in the `suggested_fix` field.
144
+ """
136
145
  return None
@@ -16,6 +16,7 @@ This agent has access to two tools:
16
16
 
17
17
  import logging
18
18
 
19
+ import langroid as lr
19
20
  from langroid.agent.chat_agent import ChatAgent, ChatAgentConfig
20
21
  from langroid.agent.chat_document import ChatDocument
21
22
  from langroid.agent.special.lance_tools import (
@@ -35,6 +36,7 @@ class LanceQueryPlanAgentConfig(ChatAgentConfig):
35
36
  doc_agent_name: str = "LanceRAG"
36
37
  doc_schema: str = ""
37
38
  use_tools = False
39
+ max_retries: int = 5 # max number of retries for query plan
38
40
  use_functions_api = True
39
41
 
40
42
  system_message = f"""
@@ -58,10 +60,13 @@ class LanceQueryPlanAgentConfig(ChatAgentConfig):
58
60
  so the REPHRASED QUERY should NOT mention ANY FILTER fields.
59
61
  The answer will answer based on documents whose CONTENTS match the QUERY,
60
62
  possibly REPHRASED.
61
- - a Pandas-dataframe calculation/aggregation string that can be used to calculate
62
- the answer to the original query, e.g. "df["rating"].mean()",
63
- or "df.groupby("director").mean()["rating"]", etc, or empty string if no calc
64
- is needed. The dataframe calc CAN refer to the `content` field.
63
+ - an OPTIONAL SINGLE-LINE Pandas-dataframe calculation/aggregation string
64
+ that can be used to calculate the answer to the original query,
65
+ e.g. "df["rating"].mean()",
66
+ or "df.groupby("director").mean()["rating"]",
67
+ or EMPTY string if no calc is needed.
68
+ The dataframe calc CAN refer to the `content` field.
69
+ If a DataFrame calculation is NOT needed, leave this field EMPTY.
65
70
 
66
71
 
67
72
  EXAMPLE:
@@ -116,6 +121,8 @@ class LanceQueryPlanAgent(ChatAgent):
116
121
  super().__init__(config)
117
122
  self.config: LanceQueryPlanAgentConfig = config
118
123
  self.curr_query_plan: QueryPlan | None = None
124
+ # how many times re-trying query plan in response to feedback:
125
+ self.n_retries: int = 0
119
126
  self.result: str = "" # answer received from LanceRAG
120
127
  # This agent should generate the QueryPlanTool
121
128
  # as well as handle it for validation
@@ -125,6 +132,8 @@ class LanceQueryPlanAgent(ChatAgent):
125
132
  def query_plan(self, msg: QueryPlanTool) -> str:
126
133
  """Valid, forward to RAG Agent"""
127
134
  # save, to be used to assemble QueryPlanResultTool
135
+ if len(msg.plan.dataframe_calc.split("\n")) > 1:
136
+ return "DATAFRAME CALCULATION must be a SINGLE LINE; Retry the `query_plan`"
128
137
  self.curr_query_plan = msg.plan
129
138
  return PASS_TO + self.config.doc_agent_name
130
139
 
@@ -132,7 +141,8 @@ class LanceQueryPlanAgent(ChatAgent):
132
141
  """Process Critic feedback on QueryPlan + Answer from RAG Agent"""
133
142
  # We should have saved answer in self.result by this time,
134
143
  # since this Agent seeks feedback only after receiving RAG answer.
135
- if msg.feedback == "":
144
+ if msg.suggested_fix == "":
145
+ self.n_retries = 0
136
146
  # This means the Query Plan or Result is good, as judged by Critic
137
147
  if self.result == "":
138
148
  # This was feedback for query with no result
@@ -141,9 +151,16 @@ class LanceQueryPlanAgent(ChatAgent):
141
151
  return NO_ANSWER
142
152
  else: # non-empty and non-null answer
143
153
  return DONE + " " + self.result
154
+ self.n_retries += 1
155
+ if self.n_retries >= self.config.max_retries:
156
+ # bail out to avoid infinite loop
157
+ self.n_retries = 0
158
+ return DONE + " " + NO_ANSWER
144
159
  return f"""
145
- here is FEEDBACK about your QUERY PLAN. Modify it if needed:
146
- {msg.feedback}
160
+ here is FEEDBACK about your QUERY PLAN, and a SUGGESTED FIX.
161
+ Modify the QUERY PLAN if needed:
162
+ FEEDBACK: {msg.feedback}
163
+ SUGGESTED FIX: {msg.suggested_fix}
147
164
  """
148
165
 
149
166
  def handle_message_fallback(
@@ -177,4 +194,14 @@ class LanceQueryPlanAgent(ChatAgent):
177
194
  response_tmpl.metadata.recipient = self.config.critic_name
178
195
  self.curr_query_plan = None # reset
179
196
  return response_tmpl
197
+ if (
198
+ isinstance(msg, ChatDocument)
199
+ and not self.has_tool_message_attempt(msg)
200
+ and msg.metadata.sender == lr.Entity.LLM
201
+ ):
202
+ # remind LLM to use the QueryPlanFeedbackTool
203
+ return """
204
+ You forgot to use the `query_plan` tool/function.
205
+ Re-try your response using the `query_plan` tool/function.
206
+ """
180
207
  return None
@@ -40,5 +40,9 @@ class QueryPlanAnswerTool(ToolMessage):
40
40
 
41
41
  class QueryPlanFeedbackTool(ToolMessage):
42
42
  request = "query_plan_feedback"
43
- purpose = "To give <feedback> regarding the query plan."
43
+ purpose = """
44
+ To give <feedback> regarding the query plan,
45
+ along with a <suggested_fix> if any (empty string if no fix is suggested).
46
+ """
44
47
  feedback: str
48
+ suggested_fix: str
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langroid
3
- Version: 0.1.243
3
+ Version: 0.1.245
4
4
  Summary: Harness LLMs with Multi-Agent Programming
5
5
  License: MIT
6
6
  Author: Prasad Chalasani
@@ -1,11 +1,11 @@
1
1
  langroid/__init__.py,sha256=zsYpGiAUsvyzZzjm964NUamsJImrXSJPVGz9a2jE_uY,1679
2
2
  langroid/agent/__init__.py,sha256=_D8dxnfdr92ch1CIrUkKjrB5HVvsQdn62b1Fb2kBxV8,785
3
- langroid/agent/base.py,sha256=jyGFmojrFuOy81lUkNsJlR6mLIOY6kOD20P9dhEcEuw,35059
3
+ langroid/agent/base.py,sha256=H1Fk9kJKr-7I1GgbmaflumG7so6yGmwl7AVTgU7PyeM,35210
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=aYuJ8M4VDHr5oymoXL2bpThM7p6P9L45fgJf3MLdkWo,20997
7
7
  langroid/agent/chat_agent.py,sha256=X5uVMm9qdw3j-FRf4hbN8k8ByaSdtQCTuU8olKE0sbs,38750
8
- langroid/agent/chat_document.py,sha256=NGr5FEWasPUQZ7cJnqrkVYYTi5fOqplSoCU-z5tTONA,8422
8
+ langroid/agent/chat_document.py,sha256=qUadrl2hiahWnvLemWCCsaCesBrfwQtOIiz2IOhUCbM,8969
9
9
  langroid/agent/helpers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  langroid/agent/junk,sha256=LxfuuW7Cijsg0szAzT81OjWWv1PMNI-6w_-DspVIO2s,339
11
11
  langroid/agent/openai_assistant.py,sha256=kIVDI4r-xGvplLU5s0nShPVHs6Jq-wOsfWE0kcMhAdQ,33056
@@ -13,10 +13,10 @@ langroid/agent/special/__init__.py,sha256=NG0JkB5y4K0bgnd9Q9UIvFExun3uTfVOWEVLVy
13
13
  langroid/agent/special/doc_chat_agent.py,sha256=LwWNb_1s5n9rOk9OpOFPuuY1VnVX5DjzQmPwBanKRrM,53763
14
14
  langroid/agent/special/lance_doc_chat_agent.py,sha256=USp0U3eTaJzwF_3bdqE7CedSLbaqAi2tm-VzygcyLaA,10175
15
15
  langroid/agent/special/lance_rag/__init__.py,sha256=QTbs0IVE2ZgDg8JJy1zN97rUUg4uEPH7SLGctFNumk4,174
16
- langroid/agent/special/lance_rag/critic_agent.py,sha256=pi_9eMBxEycbWTddtq_yz-mOb2V4SgGm3zfsOH1HU-Q,5775
16
+ langroid/agent/special/lance_rag/critic_agent.py,sha256=Xe5pCqZAnVoM-dC9_8FW5U7s2dFkPPYZ4O41BDOyHT4,6576
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=_8AwZsuEaoHGjrOrkLU2Lvxuqi4h8PkxBRcPmWPOSHk,8033
19
- langroid/agent/special/lance_tools.py,sha256=WypIS-3ZMDqY_PZEGB2K80-o4RfS43_OnER0dyFlsDY,1339
18
+ langroid/agent/special/lance_rag/query_planner_agent.py,sha256=EdkCwwx4FpM9yGlk79dd8pQx3XozUT39ss77fhDo_cU,9214
19
+ langroid/agent/special/lance_tools.py,sha256=btMwKdcT8RdwAjmzbtN1xxm3s1H7ipO9GSpUamryYx8,1456
20
20
  langroid/agent/special/neo4j/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  langroid/agent/special/neo4j/csv_kg_chat.py,sha256=koL3sKtHm3aRkLTiARs54ngrcU3lOR1WaLLc_i8rWOU,6374
22
22
  langroid/agent/special/neo4j/neo4j_chat_agent.py,sha256=vBr6EQ_eJCYAtqDe-gTSvWHT-jRE_fZOPsGWxuDJe4w,13092
@@ -121,7 +121,7 @@ langroid/vector_store/meilisearch.py,sha256=d2huA9P-NoYRuAQ9ZeXJmMKr7ry8u90RUSR2
121
121
  langroid/vector_store/momento.py,sha256=9cui31TTrILid2KIzUpBkN2Ey3g_CZWOQVdaFsA4Ors,10045
122
122
  langroid/vector_store/qdrant_cloud.py,sha256=3im4Mip0QXLkR6wiqVsjV1QvhSElfxdFSuDKddBDQ-4,188
123
123
  langroid/vector_store/qdrantdb.py,sha256=sk5Qb2ZNbooi0rorsMuqIMokF7WADw6PJ0D6goM2XBw,16802
124
- langroid-0.1.243.dist-info/LICENSE,sha256=EgVbvA6VSYgUlvC3RvPKehSg7MFaxWDsFuzLOsPPfJg,1065
125
- langroid-0.1.243.dist-info/METADATA,sha256=ifxBHFsiI6V469lHlmNq18a6ZDcItx6JvA9KKhRVTyc,49163
126
- langroid-0.1.243.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
127
- langroid-0.1.243.dist-info/RECORD,,
124
+ langroid-0.1.245.dist-info/LICENSE,sha256=EgVbvA6VSYgUlvC3RvPKehSg7MFaxWDsFuzLOsPPfJg,1065
125
+ langroid-0.1.245.dist-info/METADATA,sha256=Ucs49kPOL14MeUc2eKubI-mdxY0dfBaQlEPGKnoAy4U,49163
126
+ langroid-0.1.245.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
127
+ langroid-0.1.245.dist-info/RECORD,,