22import logging
33import uuid
44from typing import List , Literal , Optional , Union
5+ from urllib .parse import urlparse
56
67import orjson as json
78from asgiref .sync import async_to_sync
165166 },
166167}
167168
169+ CREDENTIALS_TOOL_SCHEMA = {
170+ "type" : "function" ,
171+ "function" : {
172+ "name" : "credentials" ,
173+ "description" : "Get credentials for a given domain" ,
174+ "parameters" : {
175+ "type" : "object" ,
176+ "properties" : {
177+ "domain" : {
178+ "type" : "string" ,
179+ "description" : "Domain of the website to get credentials for" ,
180+ },
181+ },
182+ "required" : ["domain" ],
183+ },
184+ },
185+ }
186+
168187TOOLS = [
169188 GOTO_TOOL_SCHEMA ,
170189 COPY_TOOL_SCHEMA ,
@@ -442,6 +461,10 @@ def _process_anthropic(self) -> dict:
442461 browser_downloads = []
443462 session_videos = []
444463
464+ credentials_tool_schema = CREDENTIALS_TOOL_SCHEMA ["function" ]
465+ credentials_tool_schema ["input_schema" ] = credentials_tool_schema ["parameters" ]
466+ del credentials_tool_schema ["parameters" ]
467+
445468 with WebBrowserClient (
446469 f"{ settings .RUNNER_HOST } :{ settings .RUNNER_PORT } " ,
447470 interactive = self ._config .stream_video ,
@@ -485,7 +508,12 @@ def _process_anthropic(self) -> dict:
485508 and isinstance (message .get ("content" ), list )
486509 and message .get ("content" )[0 ].get ("type" ) == "tool_result"
487510 ):
488- message ["content" ][0 ]["content" ] = []
511+ tool_result = message .get ("content" )[0 ]
512+ new_content = []
513+ for content in tool_result .get ("content" ):
514+ if content .get ("type" ) != "image" :
515+ new_content .append (content )
516+ tool_result ["content" ] = new_content
489517
490518 response = client .chat .completions .create (
491519 model = self ._config .provider_config .model .model_name (),
@@ -499,6 +527,7 @@ def _process_anthropic(self) -> dict:
499527 "display_height_px" : 720 ,
500528 "display_number" : 1 ,
501529 },
530+ credentials_tool_schema ,
502531 ],
503532 stream = False ,
504533 extra_headers = {"anthropic-beta" : "computer-use-2024-10-22" },
@@ -531,6 +560,43 @@ def _process_anthropic(self) -> dict:
531560 tool_responses = []
532561 for message_content in choice .message .content :
533562 if message_content .get ("type" ) == "tool_use" :
563+ if message_content .get ("name" ) == "credentials" :
564+ domain = message_content .get ("input" , {}).get ("domain" )
565+ if domain :
566+ credentials = self ._env ["connections" ][self ._config .connection_id ]["configuration" ][
567+ "credentials"
568+ ]
569+ credentials_to_use = None
570+ for credential in credentials :
571+ credential_domain = urlparse (credential .get ("domain" )).netloc or credential .get (
572+ "domain"
573+ )
574+ input_domain = urlparse (domain ).netloc or domain
575+
576+ # Compare the extracted domains
577+ if credential_domain in input_domain or input_domain in credential_domain :
578+ credentials_to_use = credential
579+ break
580+ if credentials_to_use :
581+ messages .append (
582+ {
583+ "role" : "user" ,
584+ "content" : [
585+ {
586+ "type" : "tool_result" ,
587+ "content" : [
588+ {
589+ "type" : "text" ,
590+ "text" : f"Credentials for { domain } : username: { credentials_to_use .get ('username' )} , password: { credentials_to_use .get ('password' )} " ,
591+ }
592+ ],
593+ "tool_use_id" : message_content ["id" ],
594+ }
595+ ],
596+ }
597+ )
598+ continue
599+
534600 browser_response = self ._execute_anthropic_instruction_in_browser (
535601 message_content .get ("input" , {}),
536602 web_browser = web_browser ,
0 commit comments