awslabs / multi-agent-orchestrator

Flexible and powerful framework for managing multiple AI agents and handling complex conversations
https://awslabs.github.io/multi-agent-orchestrator/
Apache License 2.0
2.12k stars 141 forks source link

Bug: AnthropicClassifier requires AWS settings? #106

Open kun432 opened 8 hours ago

kun432 commented 8 hours ago

Expected Behaviour

AnthropicClassifier only requires Anthropic API key, does not require any AWS settings like credentials or regions.

Current Behaviour

AnthropicClassifier requires AWS region settings even if I don't want to use Bedrock.

Code snippet

!pip install multi-agent-orchestrator
import getpass
import os

os.environ["ANTHROPIC_API_KEY"] = getpass.getpass('ANTHROPIC_API_KEY')
from multi_agent_orchestrator.classifiers import AnthropicClassifier, AnthropicClassifierOptions
from multi_agent_orchestrator.orchestrator import MultiAgentOrchestrator

anthropic_classifier = AnthropicClassifier(AnthropicClassifierOptions(
    api_key=os.environ["ANTHROPIC_API_KEY"]
))

resulted in NoRegionError.

---------------------------------------------------------------------------
NoRegionError                             Traceback (most recent call last)
Cell In[5], line 4
      1 from multi_agent_orchestrator.classifiers import AnthropicClassifier, AnthropicClassifierOptions
      2 from multi_agent_orchestrator.orchestrator import MultiAgentOrchestrator
----> 4 anthropic_classifier = AnthropicClassifier(AnthropicClassifierOptions(
      5     api_key=os.environ["ANTHROPIC_API_KEY"]
      6 ))

File /opt/conda/lib/python3.12/site-packages/multi_agent_orchestrator/classifiers/anthropic_classifier.py:23, in AnthropicClassifier.__init__(self, options)
     22 def __init__(self, options: AnthropicClassifierOptions):
---> 23     super().__init__()
     25     if not options.api_key:
     26         raise ValueError("Anthropic API key is required")

File /opt/conda/lib/python3.12/site-packages/multi_agent_orchestrator/classifiers/classifier.py:16, in Classifier.__init__(self)
     15 def __init__(self):
---> 16     self.default_agent = BedrockLLMAgent(
     17         options=BedrockLLMAgentOptions(
     18         name=AgentTypes.DEFAULT.value,
     19         streaming=True,
     20         description="A knowledgeable generalist capable of addressing a wide range of topics.\
     21         This agent should be selected if no other specialized agent is a better fit."
     22     ))
     24     self.agent_descriptions = ""
     25     self.history = ""

File /opt/conda/lib/python3.12/site-packages/multi_agent_orchestrator/agents/bedrock_llm_agent.py:39, in BedrockLLMAgent.__init__(self, options)
     34         self.client = boto3.client(
     35             'bedrock-runtime',
     36             region_name=options.region or os.environ.get('AWS_REGION')
     37         )
     38     else:
---> 39         self.client = boto3.client('bedrock-runtime')
     41 self.model_id: str = options.model_id or BEDROCK_MODEL_ID_CLAUDE_3_HAIKU
     42 self.streaming: bool = options.streaming

File /opt/conda/lib/python3.12/site-packages/boto3/__init__.py:92, in client(*args, **kwargs)
     86 def client(*args, **kwargs):
     87     """
     88     Create a low-level service client by name using the default session.
     89 
     90     See :py:meth:`boto3.session.Session.client`.
     91     """
---> 92     return _get_default_session().client(*args, **kwargs)

File /opt/conda/lib/python3.12/site-packages/boto3/session.py:297, in Session.client(self, service_name, region_name, api_version, use_ssl, verify, endpoint_url, aws_access_key_id, aws_secret_access_key, aws_session_token, config)
    215 def client(
    216     self,
    217     service_name,
   (...)
    226     config=None,
    227 ):
    228     """
    229     Create a low-level service client by name.
    230 
   (...)
    295 
    296     """
--> 297     return self._session.create_client(
    298         service_name,
    299         region_name=region_name,
    300         api_version=api_version,
    301         use_ssl=use_ssl,
    302         verify=verify,
    303         endpoint_url=endpoint_url,
    304         aws_access_key_id=aws_access_key_id,
    305         aws_secret_access_key=aws_secret_access_key,
    306         aws_session_token=aws_session_token,
    307         config=config,
    308     )

File /opt/conda/lib/python3.12/site-packages/botocore/session.py:997, in Session.create_client(self, service_name, region_name, api_version, use_ssl, verify, endpoint_url, aws_access_key_id, aws_secret_access_key, aws_session_token, config)
    980 self._add_configured_endpoint_provider(
    981     client_name=service_name,
    982     config_store=config_store,
    983 )
    985 client_creator = botocore.client.ClientCreator(
    986     loader,
    987     endpoint_resolver,
   (...)
    995     user_agent_creator=user_agent_creator,
    996 )
--> 997 client = client_creator.create_client(
    998     service_name=service_name,
    999     region_name=region_name,
   1000     is_secure=use_ssl,
   1001     endpoint_url=endpoint_url,
   1002     verify=verify,
   1003     credentials=credentials,
   1004     scoped_config=self.get_scoped_config(),
   1005     client_config=config,
   1006     api_version=api_version,
   1007     auth_token=auth_token,
   1008 )
   1009 monitor = self._get_internal_component('monitor')
   1010 if monitor is not None:

File /opt/conda/lib/python3.12/site-packages/botocore/client.py:161, in ClientCreator.create_client(self, service_name, region_name, is_secure, endpoint_url, verify, credentials, scoped_config, api_version, client_config, auth_token)
    148 region_name, client_config = self._normalize_fips_region(
    149     region_name, client_config
    150 )
    151 endpoint_bridge = ClientEndpointBridge(
    152     self._endpoint_resolver,
    153     scoped_config,
   (...)
    159     ),
    160 )
--> 161 client_args = self._get_client_args(
    162     service_model,
    163     region_name,
    164     is_secure,
    165     endpoint_url,
    166     verify,
    167     credentials,
    168     scoped_config,
    169     client_config,
    170     endpoint_bridge,
    171     auth_token,
    172     endpoints_ruleset_data,
    173     partition_data,
    174 )
    175 service_client = cls(**client_args)
    176 self._register_retries(service_client)

File /opt/conda/lib/python3.12/site-packages/botocore/client.py:520, in ClientCreator._get_client_args(self, service_model, region_name, is_secure, endpoint_url, verify, credentials, scoped_config, client_config, endpoint_bridge, auth_token, endpoints_ruleset_data, partition_data)
    496 def _get_client_args(
    497     self,
    498     service_model,
   (...)
    509     partition_data,
    510 ):
    511     args_creator = ClientArgsCreator(
    512         self._event_emitter,
    513         self._user_agent,
   (...)
    518         user_agent_creator=self._user_agent_creator,
    519     )
--> 520     return args_creator.get_client_args(
    521         service_model,
    522         region_name,
    523         is_secure,
    524         endpoint_url,
    525         verify,
    526         credentials,
    527         scoped_config,
    528         client_config,
    529         endpoint_bridge,
    530         auth_token,
    531         endpoints_ruleset_data,
    532         partition_data,
    533     )

File /opt/conda/lib/python3.12/site-packages/botocore/args.py:101, in ClientArgsCreator.get_client_args(self, service_model, region_name, is_secure, endpoint_url, verify, credentials, scoped_config, client_config, endpoint_bridge, auth_token, endpoints_ruleset_data, partition_data)
     86 def get_client_args(
     87     self,
     88     service_model,
   (...)
     99     partition_data=None,
    100 ):
--> 101     final_args = self.compute_client_args(
    102         service_model,
    103         client_config,
    104         endpoint_bridge,
    105         region_name,
    106         endpoint_url,
    107         is_secure,
    108         scoped_config,
    109     )
    111     service_name = final_args['service_name']  # noqa
    112     parameter_validation = final_args['parameter_validation']

File /opt/conda/lib/python3.12/site-packages/botocore/args.py:220, in ClientArgsCreator.compute_client_args(self, service_model, client_config, endpoint_bridge, region_name, endpoint_url, is_secure, scoped_config)
    213 s3_config = self.compute_s3_config(client_config)
    215 configured_endpoint_url = self._compute_configured_endpoint_url(
    216     client_config=client_config,
    217     endpoint_url=endpoint_url,
    218 )
--> 220 endpoint_config = self._compute_endpoint_config(
    221     service_name=service_name,
    222     region_name=region_name,
    223     endpoint_url=configured_endpoint_url,
    224     is_secure=is_secure,
    225     endpoint_bridge=endpoint_bridge,
    226     s3_config=s3_config,
    227 )
    228 endpoint_variant_tags = endpoint_config['metadata'].get('tags', [])
    230 # Some third-party libraries expect the final user-agent string in
    231 # ``client.meta.config.user_agent``. To maintain backwards
    232 # compatibility, the preliminary user-agent string (before any Config
    233 # object modifications and without request-specific user-agent
    234 # components) is stored in the new Config object's ``user_agent``
    235 # property but not used by Botocore itself.

File /opt/conda/lib/python3.12/site-packages/botocore/args.py:370, in ClientArgsCreator._compute_endpoint_config(self, service_name, region_name, endpoint_url, is_secure, endpoint_bridge, s3_config)
    368 if service_name == 'sts':
    369     return self._compute_sts_endpoint_config(**resolve_endpoint_kwargs)
--> 370 return self._resolve_endpoint(**resolve_endpoint_kwargs)

File /opt/conda/lib/python3.12/site-packages/botocore/args.py:475, in ClientArgsCreator._resolve_endpoint(self, service_name, region_name, endpoint_url, is_secure, endpoint_bridge)
    467 def _resolve_endpoint(
    468     self,
    469     service_name,
   (...)
    473     endpoint_bridge,
    474 ):
--> 475     return endpoint_bridge.resolve(
    476         service_name, region_name, endpoint_url, is_secure
    477     )

File /opt/conda/lib/python3.12/site-packages/botocore/client.py:625, in ClientEndpointBridge.resolve(self, service_name, region_name, endpoint_url, is_secure)
    619 use_dualstack_endpoint = self._resolve_use_dualstack_endpoint(
    620     service_name
    621 )
    622 use_fips_endpoint = self._resolve_endpoint_variant_config_var(
    623     'use_fips_endpoint'
    624 )
--> 625 resolved = self.endpoint_resolver.construct_endpoint(
    626     service_name,
    627     region_name,
    628     use_dualstack_endpoint=use_dualstack_endpoint,
    629     use_fips_endpoint=use_fips_endpoint,
    630 )
    632 # If we can't resolve the region, we'll attempt to get a global
    633 # endpoint for non-regionalized services (iam, route53, etc)
    634 if not resolved:
    635     # TODO: fallback partition_name should be configurable in the
    636     # future for users to define as needed.

File /opt/conda/lib/python3.12/site-packages/botocore/regions.py:230, in EndpointResolver.construct_endpoint(self, service_name, region_name, partition_name, use_dualstack_endpoint, use_fips_endpoint)
    225 if use_dualstack_endpoint and (
    226     partition['partition']
    227     in self._UNSUPPORTED_DUALSTACK_PARTITIONS
    228 ):
    229     continue
--> 230 result = self._endpoint_for_partition(
    231     partition,
    232     service_name,
    233     region_name,
    234     use_dualstack_endpoint,
    235     use_fips_endpoint,
    236 )
    237 if result:
    238     return result

File /opt/conda/lib/python3.12/site-packages/botocore/regions.py:278, in EndpointResolver._endpoint_for_partition(self, partition, service_name, region_name, use_dualstack_endpoint, use_fips_endpoint, force_partition)
    276         region_name = service_data['partitionEndpoint']
    277     else:
--> 278         raise NoRegionError()
    280 resolve_kwargs = {
    281     'partition': partition,
    282     'service_name': service_name,
   (...)
    286     'use_fips_endpoint': use_fips_endpoint,
    287 }
    289 # Attempt to resolve the exact region for this partition.

NoRegionError: You must specify a region.

Possible Solution

As my understanding, AnthropicClassifier does not use not Bedrock's API, but native Anthropic API. This error should not happen.

Steps to Reproduce

https://awslabs.github.io/multi-agent-orchestrator/classifiers/built-in/anthropic-classifier/

mike-adonis commented 7 hours ago

I was going to raise this bug today, glad you did.