vision-agent 0.2.85__py3-none-any.whl → 0.2.87__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.
- vision_agent/agent/vision_agent.py +49 -40
- vision_agent/tools/tool_utils.py +50 -22
- vision_agent/utils/exceptions.py +9 -0
- vision_agent/utils/execute.py +11 -0
- {vision_agent-0.2.85.dist-info → vision_agent-0.2.87.dist-info}/METADATA +1 -1
- {vision_agent-0.2.85.dist-info → vision_agent-0.2.87.dist-info}/RECORD +8 -8
- {vision_agent-0.2.85.dist-info → vision_agent-0.2.87.dist-info}/LICENSE +0 -0
- {vision_agent-0.2.85.dist-info → vision_agent-0.2.87.dist-info}/WHEEL +0 -0
@@ -172,19 +172,25 @@ def write_plans(
|
|
172
172
|
def pick_plan(
|
173
173
|
chat: List[Message],
|
174
174
|
plans: Dict[str, Any],
|
175
|
-
|
175
|
+
tool_infos: Dict[str, str],
|
176
176
|
model: LMM,
|
177
177
|
code_interpreter: CodeInterpreter,
|
178
|
+
test_multi_plan: bool,
|
178
179
|
verbosity: int = 0,
|
179
180
|
max_retries: int = 3,
|
180
|
-
) -> Tuple[str, str]:
|
181
|
+
) -> Tuple[Any, str, str]:
|
182
|
+
if not test_multi_plan:
|
183
|
+
k = list(plans.keys())[0]
|
184
|
+
return plans[k], tool_infos[k], ""
|
185
|
+
|
186
|
+
all_tool_info = tool_infos["all"]
|
181
187
|
chat = copy.deepcopy(chat)
|
182
188
|
if chat[-1]["role"] != "user":
|
183
189
|
raise ValueError("Last chat message must be from the user.")
|
184
190
|
|
185
191
|
plan_str = format_plans(plans)
|
186
192
|
prompt = TEST_PLANS.format(
|
187
|
-
docstring=
|
193
|
+
docstring=all_tool_info, plans=plan_str, previous_attempts=""
|
188
194
|
)
|
189
195
|
|
190
196
|
code = extract_code(model(prompt))
|
@@ -201,7 +207,7 @@ def pick_plan(
|
|
201
207
|
count = 0
|
202
208
|
while (not tool_output.success or tool_output_str == "") and count < max_retries:
|
203
209
|
prompt = TEST_PLANS.format(
|
204
|
-
docstring=
|
210
|
+
docstring=all_tool_info,
|
205
211
|
plans=plan_str,
|
206
212
|
previous_attempts=PREVIOUS_FAILED.format(
|
207
213
|
code=code, error=tool_output.text()
|
@@ -237,7 +243,17 @@ def pick_plan(
|
|
237
243
|
best_plan = extract_json(model(chat))
|
238
244
|
if verbosity >= 1:
|
239
245
|
_LOGGER.info(f"Best plan:\n{best_plan}")
|
240
|
-
|
246
|
+
|
247
|
+
plan = best_plan["best_plan"]
|
248
|
+
if plan in plans and plan in tool_infos:
|
249
|
+
return plans[plan], tool_infos[plan], tool_output_str
|
250
|
+
else:
|
251
|
+
if verbosity >= 1:
|
252
|
+
_LOGGER.warning(
|
253
|
+
f"Best plan {plan} not found in plans or tool_infos. Using the first plan and tool info."
|
254
|
+
)
|
255
|
+
k = list(plans.keys())[0]
|
256
|
+
return plans[k], tool_infos[k], tool_output_str
|
241
257
|
|
242
258
|
|
243
259
|
@traceable
|
@@ -524,6 +540,13 @@ def retrieve_tools(
|
|
524
540
|
)
|
525
541
|
all_tools = "\n\n".join(set(tool_info))
|
526
542
|
tool_lists_unique["all"] = all_tools
|
543
|
+
log_progress(
|
544
|
+
{
|
545
|
+
"type": "tools",
|
546
|
+
"status": "completed",
|
547
|
+
"payload": tool_lists[list(plans.keys())[0]],
|
548
|
+
}
|
549
|
+
)
|
527
550
|
return tool_lists_unique
|
528
551
|
|
529
552
|
|
@@ -692,6 +715,14 @@ class VisionAgent(Agent):
|
|
692
715
|
self.planner,
|
693
716
|
)
|
694
717
|
|
718
|
+
self.log_progress(
|
719
|
+
{
|
720
|
+
"type": "plans",
|
721
|
+
"status": "completed",
|
722
|
+
"payload": plans[list(plans.keys())[0]],
|
723
|
+
}
|
724
|
+
)
|
725
|
+
|
695
726
|
if self.verbosity >= 1 and test_multi_plan:
|
696
727
|
for p in plans:
|
697
728
|
_LOGGER.info(
|
@@ -705,47 +736,25 @@ class VisionAgent(Agent):
|
|
705
736
|
self.verbosity,
|
706
737
|
)
|
707
738
|
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
)
|
717
|
-
else:
|
718
|
-
best_plan = list(plans.keys())[0]
|
719
|
-
tool_output_str = ""
|
720
|
-
|
721
|
-
if best_plan in plans and best_plan in tool_infos:
|
722
|
-
plan_i = plans[best_plan]
|
723
|
-
tool_info = tool_infos[best_plan]
|
724
|
-
else:
|
725
|
-
if self.verbosity >= 1:
|
726
|
-
_LOGGER.warning(
|
727
|
-
f"Best plan {best_plan} not found in plans or tool_infos. Using the first plan and tool info."
|
728
|
-
)
|
729
|
-
k = list(plans.keys())[0]
|
730
|
-
plan_i = plans[k]
|
731
|
-
tool_info = tool_infos[k]
|
732
|
-
|
733
|
-
self.log_progress(
|
734
|
-
{
|
735
|
-
"type": "plans",
|
736
|
-
"status": "completed",
|
737
|
-
"payload": plan_i,
|
738
|
-
}
|
739
|
+
best_plan, best_tool_info, tool_output_str = pick_plan(
|
740
|
+
int_chat,
|
741
|
+
plans,
|
742
|
+
tool_infos,
|
743
|
+
self.coder,
|
744
|
+
code_interpreter,
|
745
|
+
test_multi_plan,
|
746
|
+
verbosity=self.verbosity,
|
739
747
|
)
|
748
|
+
|
740
749
|
if self.verbosity >= 1:
|
741
750
|
_LOGGER.info(
|
742
|
-
f"Picked best plan:\n{tabulate(tabular_data=
|
751
|
+
f"Picked best plan:\n{tabulate(tabular_data=best_plan, headers='keys', tablefmt='mixed_grid', maxcolwidths=_MAX_TABULATE_COL_WIDTH)}"
|
743
752
|
)
|
744
753
|
|
745
754
|
results = write_and_test_code(
|
746
755
|
chat=[{"role": c["role"], "content": c["content"]} for c in int_chat],
|
747
|
-
plan="\n-" + "\n-".join([e["instructions"] for e in
|
748
|
-
tool_info=
|
756
|
+
plan="\n-" + "\n-".join([e["instructions"] for e in best_plan]),
|
757
|
+
tool_info=best_tool_info,
|
749
758
|
tool_output=tool_output_str,
|
750
759
|
tool_utils=T.UTILITIES_DOCSTRING,
|
751
760
|
working_memory=working_memory,
|
@@ -761,7 +770,7 @@ class VisionAgent(Agent):
|
|
761
770
|
code = cast(str, results["code"])
|
762
771
|
test = cast(str, results["test"])
|
763
772
|
working_memory.extend(results["working_memory"]) # type: ignore
|
764
|
-
plan.append({"code": code, "test": test, "plan":
|
773
|
+
plan.append({"code": code, "test": test, "plan": best_plan})
|
765
774
|
|
766
775
|
execution_result = cast(Execution, results["test_result"])
|
767
776
|
self.log_progress(
|
vision_agent/tools/tool_utils.py
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
import logging
|
2
2
|
import os
|
3
|
-
from typing import Any, Dict
|
3
|
+
from typing import Any, Dict, MutableMapping, Optional
|
4
4
|
|
5
|
+
from IPython.display import display
|
6
|
+
from pydantic import BaseModel
|
5
7
|
from requests import Session
|
6
8
|
from requests.adapters import HTTPAdapter
|
7
9
|
from urllib3.util.retry import Retry
|
8
10
|
|
11
|
+
from vision_agent.utils.exceptions import RemoteToolCallFailed
|
12
|
+
from vision_agent.utils.execute import Error, MimeType
|
9
13
|
from vision_agent.utils.type_defs import LandingaiAPIKey
|
10
14
|
|
11
15
|
_LOGGER = logging.getLogger(__name__)
|
@@ -13,34 +17,58 @@ _LND_API_KEY = LandingaiAPIKey().api_key
|
|
13
17
|
_LND_API_URL = "https://api.staging.landing.ai/v1/agent"
|
14
18
|
|
15
19
|
|
20
|
+
class ToolCallTrace(BaseModel):
|
21
|
+
endpoint_url: str
|
22
|
+
request: MutableMapping[str, Any]
|
23
|
+
response: MutableMapping[str, Any]
|
24
|
+
error: Optional[Error]
|
25
|
+
|
26
|
+
|
16
27
|
def send_inference_request(
|
17
28
|
payload: Dict[str, Any], endpoint_name: str
|
18
29
|
) -> Dict[str, Any]:
|
19
|
-
|
20
|
-
|
30
|
+
try:
|
31
|
+
if runtime_tag := os.environ.get("RUNTIME_TAG", ""):
|
32
|
+
payload["runtime_tag"] = runtime_tag
|
21
33
|
|
22
|
-
|
23
|
-
|
24
|
-
|
34
|
+
url = f"{_LND_API_URL}/model/{endpoint_name}"
|
35
|
+
if "TOOL_ENDPOINT_URL" in os.environ:
|
36
|
+
url = os.environ["TOOL_ENDPOINT_URL"]
|
25
37
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
38
|
+
tool_call_trace = ToolCallTrace(
|
39
|
+
endpoint_url=url,
|
40
|
+
request=payload,
|
41
|
+
response={},
|
42
|
+
error=None,
|
43
|
+
)
|
44
|
+
headers = {"Content-Type": "application/json", "apikey": _LND_API_KEY}
|
45
|
+
if "TOOL_ENDPOINT_AUTH" in os.environ:
|
46
|
+
headers["Authorization"] = os.environ["TOOL_ENDPOINT_AUTH"]
|
47
|
+
headers.pop("apikey")
|
30
48
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
49
|
+
session = _create_requests_session(
|
50
|
+
url=url,
|
51
|
+
num_retry=3,
|
52
|
+
headers=headers,
|
53
|
+
)
|
54
|
+
res = session.post(url, json=payload)
|
55
|
+
if res.status_code != 200:
|
56
|
+
tool_call_trace.error = Error(
|
57
|
+
name="RemoteToolCallFailed",
|
58
|
+
value=f"{res.status_code} - {res.text}",
|
59
|
+
traceback_raw=[],
|
60
|
+
)
|
61
|
+
_LOGGER.error(f"Request failed: {res.status_code} {res.text}")
|
62
|
+
raise RemoteToolCallFailed(payload["tool"], res.status_code, res.text)
|
40
63
|
|
41
|
-
|
42
|
-
|
43
|
-
|
64
|
+
resp = res.json()
|
65
|
+
tool_call_trace.response = resp
|
66
|
+
# TODO: consider making the response schema the same between below two sources
|
67
|
+
return resp if "TOOL_ENDPOINT_AUTH" in os.environ else resp["data"] # type: ignore
|
68
|
+
finally:
|
69
|
+
trace = tool_call_trace.model_dump()
|
70
|
+
trace["type"] = "tool_call"
|
71
|
+
display({MimeType.APPLICATION_JSON: trace}, raw=True)
|
44
72
|
|
45
73
|
|
46
74
|
def _create_requests_session(
|
vision_agent/utils/exceptions.py
CHANGED
@@ -13,6 +13,15 @@ For more information, see https://landing-ai.github.io/landingai-python/landinga
|
|
13
13
|
return self.message
|
14
14
|
|
15
15
|
|
16
|
+
class RemoteToolCallFailed(Exception):
|
17
|
+
"""Exception raised when an error occurs during a tool call."""
|
18
|
+
|
19
|
+
def __init__(self, tool_name: str, status_code: int, message: str):
|
20
|
+
self.message = (
|
21
|
+
f"""Tool call ({tool_name}) failed due to {status_code} - {message}"""
|
22
|
+
)
|
23
|
+
|
24
|
+
|
16
25
|
class RemoteSandboxError(Exception):
|
17
26
|
"""Exception related to remote sandbox."""
|
18
27
|
|
vision_agent/utils/execute.py
CHANGED
@@ -277,6 +277,17 @@ class Error(BaseModel):
|
|
277
277
|
text = "\n".join(self.traceback_raw)
|
278
278
|
return _remove_escape_and_color_codes(text) if return_clean_text else text
|
279
279
|
|
280
|
+
@staticmethod
|
281
|
+
def from_exception(e: Exception) -> "Error":
|
282
|
+
"""
|
283
|
+
Creates an Error object from an exception.
|
284
|
+
"""
|
285
|
+
return Error(
|
286
|
+
name=e.__class__.__name__,
|
287
|
+
value=str(e),
|
288
|
+
traceback_raw=traceback.format_exception(type(e), e, e.__traceback__),
|
289
|
+
)
|
290
|
+
|
280
291
|
|
281
292
|
class Execution(BaseModel):
|
282
293
|
"""
|
@@ -1,7 +1,7 @@
|
|
1
1
|
vision_agent/__init__.py,sha256=EAb4-f9iyuEYkBrX4ag1syM8Syx8118_t0R6_C34M9w,57
|
2
2
|
vision_agent/agent/__init__.py,sha256=IUwfbPMcT8X_rnXMLmI8gJ4ltsHy_XSs9eLiKURJxeY,81
|
3
3
|
vision_agent/agent/agent.py,sha256=ZK-5lOtd9-eD9aWcXssJpnOyvZuO7_5hAmnb-6sWVe8,569
|
4
|
-
vision_agent/agent/vision_agent.py,sha256=
|
4
|
+
vision_agent/agent/vision_agent.py,sha256=MVZmwIk7U7PMwzyqKwhqAI-8Lw1E-X_PdSK9vDmbxxk,29125
|
5
5
|
vision_agent/agent/vision_agent_prompts.py,sha256=brBV-SmzyzTG5M9nfV3R5xdYT_BUYOKzxNFmTa2Sp-o,11049
|
6
6
|
vision_agent/fonts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
7
|
vision_agent/fonts/default_font_ch_en.ttf,sha256=1YM0Z3XqLDjSNbF7ihQFSAIUdjF9m1rtHiNC_6QosTE,1594400
|
@@ -9,16 +9,16 @@ vision_agent/lmm/__init__.py,sha256=j9mQsIXQOYfW6nFd47uTwuBe1ranpEbwW308qLfCWN0,
|
|
9
9
|
vision_agent/lmm/lmm.py,sha256=035uONyp6_jD3PVdNdSg2PMHOG1voqnpsn2IyybUENs,15147
|
10
10
|
vision_agent/tools/__init__.py,sha256=k69hvcy2FWjDqVA0klzybKeoToOH_bom5NTVSliA0Og,1838
|
11
11
|
vision_agent/tools/prompts.py,sha256=V1z4YJLXZuUl_iZ5rY0M5hHc_2tmMEUKr0WocXKGt4E,1430
|
12
|
-
vision_agent/tools/tool_utils.py,sha256=
|
12
|
+
vision_agent/tools/tool_utils.py,sha256=ZnqaflVbLZB0GmgJJoQsZZs8hWbODXEPH1_Mq1s4bnc,3222
|
13
13
|
vision_agent/tools/tools.py,sha256=TkZqNYX-ocwdaCdXd6c6tysSa_HX2y6Nrgl4JKni4IQ,43661
|
14
14
|
vision_agent/utils/__init__.py,sha256=CW84HnhqI6XQVuxf2KifkLnSuO7EOhmuL09-gAymAak,219
|
15
|
-
vision_agent/utils/exceptions.py,sha256=
|
16
|
-
vision_agent/utils/execute.py,sha256=
|
15
|
+
vision_agent/utils/exceptions.py,sha256=isVH-SVL4vHj3q5kK4z7cy5_aOapAqHXWkpibfSNbUs,1659
|
16
|
+
vision_agent/utils/execute.py,sha256=DxuAoKmKAovgKe8IPkwg1B34osoz9_Ouvl1mi8aPXgE,23923
|
17
17
|
vision_agent/utils/image_utils.py,sha256=_cdiS5YrLzqkq_ZgFUO897m5M4_SCIThwUy4lOklfB8,7700
|
18
18
|
vision_agent/utils/sim.py,sha256=1HTaiVaBiKeyXIy21IYGXlPw0TipOyw9FPOJDfyLI94,4409
|
19
19
|
vision_agent/utils/type_defs.py,sha256=QeQRRIlklZMWzxROcCn5ELxP89nYdXGydy1rAiSpZZw,1384
|
20
20
|
vision_agent/utils/video.py,sha256=rNmU9KEIkZB5-EztZNlUiKYN0mm_55A_2VGUM0QpqLA,8779
|
21
|
-
vision_agent-0.2.
|
22
|
-
vision_agent-0.2.
|
23
|
-
vision_agent-0.2.
|
24
|
-
vision_agent-0.2.
|
21
|
+
vision_agent-0.2.87.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
22
|
+
vision_agent-0.2.87.dist-info/METADATA,sha256=St27tw1lvdjylYwUHeM3928tAzGeJjCj879nMJA-OWw,9477
|
23
|
+
vision_agent-0.2.87.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
24
|
+
vision_agent-0.2.87.dist-info/RECORD,,
|
File without changes
|
File without changes
|