Skip to content

Commit 5b641bf

Browse files
committed
Handle empty command output
1 parent 6886d1f commit 5b641bf

File tree

1 file changed

+79
-68
lines changed

1 file changed

+79
-68
lines changed

llmstack/processors/providers/promptly/web_browser.py

Lines changed: 79 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from langrocks.client import WebBrowser as WebBrowserClient
1212
from langrocks.common.models.web_browser import (
1313
WebBrowserCommand,
14-
WebBrowserCommandOutput,
1514
WebBrowserCommandType,
1615
WebBrowserContent,
1716
)
@@ -470,14 +469,7 @@ def _execute_anthropic_instruction_in_browser(
470469
)
471470
else:
472471
logger.error(f"Invalid instruction: {instruction_input}")
473-
return WebBrowserContent(
474-
command_outputs=[
475-
WebBrowserCommandOutput(
476-
index=0,
477-
output="We do not currently support this action",
478-
)
479-
],
480-
)
472+
return None
481473

482474
def _process_anthropic(self) -> dict:
483475
client = get_llm_client_from_provider_config(
@@ -579,20 +571,18 @@ def _process_anthropic(self) -> dict:
579571
max_tokens=4096,
580572
)
581573
if response.usage:
582-
self._usage_data.append(
583-
(
584-
f"{self._config.provider_config.provider}/*/{self._config.provider_config.model.model_name()}/*",
585-
MetricType.INPUT_TOKENS,
586-
(provider_config.provider_config_source, response.usage.get_input_tokens()),
587-
)
588-
)
589-
self._usage_data.append(
590-
(
591-
f"{self._config.provider_config.provider}/*/{self._config.provider_config.model.model_name()}/*",
592-
MetricType.OUTPUT_TOKENS,
593-
(provider_config.provider_config_source, response.usage.get_output_tokens()),
574+
for metric_type, token_getter in [
575+
(MetricType.INPUT_TOKENS, response.usage.get_input_tokens),
576+
(MetricType.OUTPUT_TOKENS, response.usage.get_output_tokens),
577+
]:
578+
self._usage_data.append(
579+
(
580+
f"{self._config.provider_config.provider}/*/{self._config.provider_config.model.model_name()}/*",
581+
metric_type,
582+
(provider_config.provider_config_source, token_getter()),
583+
)
594584
)
595-
)
585+
596586
choice = response.choices[0]
597587
# Append to history of messages
598588
messages.append(
@@ -601,6 +591,15 @@ def _process_anthropic(self) -> dict:
601591
"content": choice.message.content,
602592
}
603593
)
594+
595+
def create_tool_response(content, tool_use_id, is_error=False):
596+
return {
597+
"type": "tool_result",
598+
"content": [content],
599+
"tool_use_id": tool_use_id,
600+
"is_error": is_error,
601+
}
602+
604603
if choice.finish_reason == "tool_use":
605604
tool_responses = []
606605
for message_content in choice.message.content:
@@ -618,7 +617,6 @@ def _process_anthropic(self) -> dict:
618617
)
619618
input_domain = urlparse(domain).netloc or domain
620619

621-
# Compare the extracted domains
622620
if credential_domain in input_domain or input_domain in credential_domain:
623621
credentials_to_use = credential
624622
break
@@ -627,16 +625,13 @@ def _process_anthropic(self) -> dict:
627625
{
628626
"role": "user",
629627
"content": [
630-
{
631-
"type": "tool_result",
632-
"content": [
633-
{
634-
"type": "text",
635-
"text": f"Credentials for {domain}: username: {credentials_to_use.get('username')}, password: {credentials_to_use.get('password')}",
636-
}
637-
],
638-
"tool_use_id": message_content["id"],
639-
}
628+
create_tool_response(
629+
{
630+
"type": "text",
631+
"text": f"Credentials for {domain}: username: {credentials_to_use.get('username')}, password: {credentials_to_use.get('password')}",
632+
},
633+
message_content["id"],
634+
)
640635
],
641636
}
642637
)
@@ -647,52 +642,68 @@ def _process_anthropic(self) -> dict:
647642
web_browser=web_browser,
648643
prev_browser_state=browser_response,
649644
)
650-
if browser_response.downloads:
651-
browser_downloads.extend(browser_response.downloads)
652-
command_output = browser_response.command_outputs[0]
653-
if message_content.get("input", {}).get("action") == "screenshot":
645+
if browser_response is None:
654646
tool_responses.append(
655-
{
656-
"type": "tool_result",
657-
"content": [
658-
{
659-
"type": "image",
660-
"source": {
661-
"type": "base64",
662-
"media_type": "image/png",
663-
"data": command_output.output,
664-
},
665-
},
666-
],
667-
"tool_use_id": message_content["id"],
668-
"is_error": False,
669-
}
647+
create_tool_response(
648+
{"type": "text", "text": "We do not currently support this action"},
649+
message_content["id"],
650+
is_error=True,
651+
)
670652
)
671653
else:
672-
tool_responses.append(
673-
{
674-
"type": "tool_result",
675-
"content": [
654+
if browser_response.downloads:
655+
browser_downloads.extend(browser_response.downloads)
656+
657+
is_screenshot = message_content.get("input", {}).get("action") == "screenshot"
658+
command_output = (
659+
browser_response.command_outputs[0] if browser_response.command_outputs else None
660+
)
661+
command_error = (
662+
browser_response.command_errors[0].error
663+
if browser_response.command_errors
664+
else None
665+
)
666+
667+
if command_output and command_output.output:
668+
content = {
669+
"type": "image" if is_screenshot else "text",
670+
"source"
671+
if is_screenshot
672+
else "text": (
673+
{
674+
"type": "base64",
675+
"media_type": "image/png",
676+
"data": command_output.output,
677+
}
678+
if is_screenshot
679+
else command_output.output
680+
),
681+
}
682+
tool_responses.append(create_tool_response(content, message_content["id"]))
683+
else:
684+
screenshot_error_text = (
685+
command_error.error if command_error else "No screenshot available"
686+
)
687+
output_error_text = command_error.error if command_error else "No output available"
688+
tool_responses.append(
689+
create_tool_response(
676690
{
677691
"type": "text",
678-
"text": command_output.output,
692+
"text": screenshot_error_text if is_screenshot else output_error_text,
679693
},
680-
],
681-
"tool_use_id": message_content["id"],
682-
"is_error": False,
683-
}
684-
)
694+
message_content["id"],
695+
is_error=True,
696+
)
697+
)
698+
logger.error(
699+
f"No command output for tool use: {message_content.get('input', {})}. Error: {command_error}",
700+
)
685701
else:
686702
async_to_sync(self._output_stream.write)(
687703
WebBrowserOutput(text=message_content.get("text", "") + "\n\n"),
688704
)
689705
if tool_responses:
690-
messages.append(
691-
{
692-
"role": "user",
693-
"content": tool_responses,
694-
}
695-
)
706+
messages.append({"role": "user", "content": tool_responses})
696707
continue
697708
elif choice.finish_reason == "end_turn":
698709
browser_response = web_browser.run_commands(

0 commit comments

Comments
 (0)