When building Python tools that consume connections, you must explicitly define each expected connection in the expected_credentials array within the @tool decorator.If your Python file includes multiple tools, each tool must declare its own expected_credentials. This ensures that the tool can fetch the necessary connections during execution. Include all connections used directly within the tool function, as well as those used in any helper functions the tool calls.If you attempt to import a tool with a connection type that doesn’t match one of the expected types for the specified app_id, the orchestrate tools import command will fail and prevent the tool from being imported.
Combining multiple connection types for a single application id
You can define multiple authentication types for a single app_id, which is useful when using different methods in different environments—for example, basic authentication in draft mode and OAuth in production.To support this, provide an array of credential types in the expected_credentials field instead of a single type. At runtime, your Python tool must determine which connection type to use by calling:
PYTHON
connections.connection_type('my-app')
Make sure the tool handles disambiguation logic appropriately. If the connection type provided during import doesn’t match any of the expected types for the specified app_id, the orchestrate tools import command will fail and block the import.
PYTHON
from ibm_watsonx_orchestrate.agent_builder.tools import toolfrom ibm_watsonx_orchestrate.agent_builder.connections import ConnectionTypefrom ibm_watsonx_orchestrate.run import connectionsMY_APP_ID='app-id'MY_APP_ID2='app-id-2'@tool( expected_credentials=[ {"app_id": MY_APP_ID, "type": ConnectionType.KEY_VALUE}, {"app_id": MY_APP_ID2, "type": [ConnectionType.API_KEY_AUTH, ConnectionType.OAUTH2_CLIENT_CREDS]} ])def my_tool(): headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' # key value connections hold any arbitrary dictionary of keys and values 'x-client-id': connections.key_value(MY_APP_ID)['client-id'] } url = None connection_type = connections.connection_type(MY_APP_ID2) if connection_type == ConnectionType.API_KEY_AUTH: conn = connections.api_key_auth(MY_APP_ID2) url = conn.url headers['x-api-key'] = conn.api_key elif connection_type == ConnectionType.OAUTH2_CLIENT_CREDS: # oauth connections contain a url and an access token generated within orchestrate and exposed to your tool url = conn.url conn = connections.oauth2_client_creds(MY_APP_ID2) headers['Authorization'] = f"Bearer {conn.access_token}" else: raise ValueError(f"Unexpected connection type {connection_type} for {MY_APP_ID2}") response = requests.post( url, headers=headers, json={} ) response.raise_for_status() return response.json()['result']
To import a Python tool that uses connections, use the -a app_id flag to bind each connection to the tool:
BASH
orchestrate tools import -k python \ -f my_tool.py \ -a app_1 \ -a app_2
If your tool expects a specific connection ID in your file, but the actual connection in Orchestrate uses a different name, you can remap it using the -a flag:
When debugging Python tools outside watsonx Orchestrate, you can run them locally by emulating the environment variables that Orchestrate sets at runtime. These variables expose connection credentials to your tool, allowing you to test functionality without deploying the tool.
Orchestrate uses the following naming convention to expose connections: