ibm-watsonx-orchestrate 1.6.0b0__py3-none-any.whl → 1.6.1__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.
Files changed (42) hide show
  1. ibm_watsonx_orchestrate/__init__.py +1 -1
  2. ibm_watsonx_orchestrate/agent_builder/agents/agent.py +1 -0
  3. ibm_watsonx_orchestrate/agent_builder/agents/types.py +5 -1
  4. ibm_watsonx_orchestrate/agent_builder/agents/webchat_customizations/__init__.py +2 -0
  5. ibm_watsonx_orchestrate/agent_builder/agents/webchat_customizations/prompts.py +34 -0
  6. ibm_watsonx_orchestrate/agent_builder/agents/webchat_customizations/welcome_content.py +20 -0
  7. ibm_watsonx_orchestrate/agent_builder/connections/__init__.py +2 -2
  8. ibm_watsonx_orchestrate/agent_builder/connections/connections.py +21 -7
  9. ibm_watsonx_orchestrate/agent_builder/connections/types.py +39 -36
  10. ibm_watsonx_orchestrate/agent_builder/tools/flow_tool.py +83 -0
  11. ibm_watsonx_orchestrate/agent_builder/tools/types.py +7 -1
  12. ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +56 -18
  13. ibm_watsonx_orchestrate/cli/commands/channels/webchat/channels_webchat_controller.py +104 -21
  14. ibm_watsonx_orchestrate/cli/commands/chat/chat_command.py +2 -0
  15. ibm_watsonx_orchestrate/cli/commands/connections/connections_command.py +26 -18
  16. ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +61 -61
  17. ibm_watsonx_orchestrate/cli/commands/environment/environment_controller.py +1 -1
  18. ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_command.py +118 -30
  19. ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_controller.py +22 -9
  20. ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_controller.py +2 -2
  21. ibm_watsonx_orchestrate/cli/commands/server/server_command.py +123 -5
  22. ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_controller.py +9 -3
  23. ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +107 -22
  24. ibm_watsonx_orchestrate/client/agents/agent_client.py +74 -6
  25. ibm_watsonx_orchestrate/client/base_api_client.py +2 -1
  26. ibm_watsonx_orchestrate/client/connections/connections_client.py +18 -9
  27. ibm_watsonx_orchestrate/client/connections/utils.py +4 -2
  28. ibm_watsonx_orchestrate/client/local_service_instance.py +1 -1
  29. ibm_watsonx_orchestrate/client/service_instance.py +3 -3
  30. ibm_watsonx_orchestrate/client/tools/tempus_client.py +8 -3
  31. ibm_watsonx_orchestrate/client/utils.py +10 -0
  32. ibm_watsonx_orchestrate/docker/compose-lite.yml +228 -67
  33. ibm_watsonx_orchestrate/docker/default.env +32 -13
  34. ibm_watsonx_orchestrate/docker/proxy-config-single.yaml +12 -0
  35. ibm_watsonx_orchestrate/flow_builder/flows/flow.py +15 -5
  36. ibm_watsonx_orchestrate/flow_builder/utils.py +78 -48
  37. ibm_watsonx_orchestrate/run/connections.py +4 -4
  38. {ibm_watsonx_orchestrate-1.6.0b0.dist-info → ibm_watsonx_orchestrate-1.6.1.dist-info}/METADATA +2 -2
  39. {ibm_watsonx_orchestrate-1.6.0b0.dist-info → ibm_watsonx_orchestrate-1.6.1.dist-info}/RECORD +42 -37
  40. {ibm_watsonx_orchestrate-1.6.0b0.dist-info → ibm_watsonx_orchestrate-1.6.1.dist-info}/WHEEL +0 -0
  41. {ibm_watsonx_orchestrate-1.6.0b0.dist-info → ibm_watsonx_orchestrate-1.6.1.dist-info}/entry_points.txt +0 -0
  42. {ibm_watsonx_orchestrate-1.6.0b0.dist-info → ibm_watsonx_orchestrate-1.6.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,9 +1,10 @@
1
1
  import logging
2
2
  import rich
3
3
  import jwt
4
+ import sys
4
5
 
5
6
  from ibm_watsonx_orchestrate.cli.config import Config, ENV_WXO_URL_OPT, ENVIRONMENTS_SECTION_HEADER, CONTEXT_SECTION_HEADER, CONTEXT_ACTIVE_ENV_OPT, CHAT_UI_PORT
6
- from ibm_watsonx_orchestrate.client.utils import is_local_dev, AUTH_CONFIG_FILE_FOLDER, AUTH_SECTION_HEADER, AUTH_MCSP_TOKEN_OPT, AUTH_CONFIG_FILE
7
+ from ibm_watsonx_orchestrate.client.utils import is_local_dev, is_ibm_cloud, AUTH_CONFIG_FILE_FOLDER, AUTH_SECTION_HEADER, AUTH_MCSP_TOKEN_OPT, AUTH_CONFIG_FILE
7
8
 
8
9
  from ibm_watsonx_orchestrate.client.agents.agent_client import AgentClient
9
10
 
@@ -19,7 +20,41 @@ class ChannelsWebchatController:
19
20
  def get_native_client(self):
20
21
  self.native_client = instantiate_client(AgentClient)
21
22
  return self.native_client
22
-
23
+
24
+ def extract_tenant_id_from_crn(self, crn: str) -> str:
25
+ is_ibm_cloud_env = is_ibm_cloud()
26
+ if is_ibm_cloud_env:
27
+ try:
28
+ parts = crn.split("a/")[1].split(":")
29
+ account_part = parts[0]
30
+ instance_part = parts[1]
31
+ tenant_id = f"{account_part}_{instance_part}"
32
+ return tenant_id
33
+ except (IndexError, AttributeError):
34
+ raise ValueError(f"Invalid CRN format: {crn}")
35
+ else:
36
+ try:
37
+ parts = crn.split("sub/")[1].split(":")
38
+ account_part = parts[0]
39
+ instance_part = parts[1]
40
+ tenant_id = f"{account_part}_{instance_part}"
41
+ return tenant_id
42
+ except (IndexError, AttributeError):
43
+ raise ValueError(f"Invalid CRN format: {crn}")
44
+
45
+
46
+
47
+ def check_crn_is_correct(self, crn: str):
48
+ parts = crn.split("a/")[1].split(":")
49
+ instance_part_crn = parts[1]
50
+ cfg = Config()
51
+ active_env = cfg.read(CONTEXT_SECTION_HEADER, CONTEXT_ACTIVE_ENV_OPT)
52
+ url = cfg.get(ENVIRONMENTS_SECTION_HEADER, active_env, ENV_WXO_URL_OPT)
53
+ instance_part_url = url.rstrip("/").split("/")[-1]
54
+ if instance_part_crn == instance_part_url:
55
+ return True
56
+ else:
57
+ return False
23
58
 
24
59
  def get_agent_id(self, agent_name: str):
25
60
  native_client = self.get_native_client()
@@ -39,7 +74,7 @@ class ChannelsWebchatController:
39
74
  raise ValueError(f"No agent found with the name '{agent_name}'")
40
75
 
41
76
  agent = existing_native_agents[0]
42
- agent_environments = agent.get("environments", [])
77
+ agent_environments = agent.get("environments", [])
43
78
 
44
79
  is_local = is_local_dev()
45
80
  target_env = env or 'draft'
@@ -56,15 +91,37 @@ class ChannelsWebchatController:
56
91
  logger.error(f'This agent does not exist in the {env} environment. You need to deploy it to {env} before you can embed the agent')
57
92
  exit(1)
58
93
 
59
- return filtered_environments[0].get("id")
94
+ if target_env == 'draft' and is_local == False:
95
+ logger.error(f'For SAAS, please ensure this agent exists in a Live Environment')
96
+ exit(1)
97
+
60
98
 
61
99
 
100
+ return filtered_environments[0].get("id")
101
+
62
102
  def get_tennent_id(self):
63
103
  auth_cfg = Config(AUTH_CONFIG_FILE_FOLDER, AUTH_CONFIG_FILE)
64
104
 
65
105
  cfg = Config()
66
106
  active_env = cfg.read(CONTEXT_SECTION_HEADER, CONTEXT_ACTIVE_ENV_OPT)
67
- is_local = is_local_dev()
107
+
108
+ existing_auth_config = auth_cfg.get(AUTH_SECTION_HEADER).get(active_env, {})
109
+
110
+ existing_token = existing_auth_config.get(AUTH_MCSP_TOKEN_OPT) if existing_auth_config else None
111
+ token = jwt.decode(existing_token, options={"verify_signature": False})
112
+ crn = ""
113
+ crn = token.get('aud', None)
114
+
115
+ tenant_id = self.extract_tenant_id_from_crn(crn)
116
+ return tenant_id
117
+
118
+
119
+
120
+ def get_tenant_id_local(self):
121
+ auth_cfg = Config(AUTH_CONFIG_FILE_FOLDER, AUTH_CONFIG_FILE)
122
+
123
+ cfg = Config()
124
+ active_env = cfg.read(CONTEXT_SECTION_HEADER, CONTEXT_ACTIVE_ENV_OPT)
68
125
 
69
126
  existing_auth_config = auth_cfg.get(AUTH_SECTION_HEADER).get(active_env, {})
70
127
 
@@ -72,10 +129,7 @@ class ChannelsWebchatController:
72
129
 
73
130
  token = jwt.decode(existing_token, options={"verify_signature": False})
74
131
  tenant_id = ""
75
- if is_local:
76
- tenant_id = token.get('woTenantId', None)
77
- else:
78
- tenant_id = token.get('tenantId', None)
132
+ tenant_id = token.get('woTenantId', None)
79
133
 
80
134
  return tenant_id
81
135
 
@@ -99,41 +153,70 @@ class ChannelsWebchatController:
99
153
 
100
154
 
101
155
  def create_webchat_embed_code(self):
102
- tenant_id = self.get_tennent_id()
156
+ crn = None
157
+ is_ibm_cloud_env = is_ibm_cloud()
158
+ is_local = is_local_dev()
159
+ if is_ibm_cloud_env is True:
160
+ crn = input("Please enter your CRN which can be gotten from the IBM Cloud UI: ")
161
+ if crn == "":
162
+ logger.error("You must enter your CRN for IBM Cloud instances")
163
+ sys.exit(1)
164
+ is_crn_correct = self.check_crn_is_correct(crn)
165
+ if is_crn_correct == False:
166
+ logger.error("Invalid CRN format provided.")
167
+
168
+ if is_ibm_cloud_env and crn is not None:
169
+ tenant_id = self.extract_tenant_id_from_crn(crn)
170
+ elif is_ibm_cloud_env is False and is_local is False:
171
+ tenant_id = self.get_tennent_id()
172
+ elif is_local:
173
+ tenant_id = self.get_tenant_id_local()
103
174
  host_url = self.get_host_url()
104
175
  agent_id = self.get_agent_id(self.agent_name)
105
176
  agent_env_id = self.get_environment_id(self.agent_name, self.env)
106
177
 
107
- is_local = is_local_dev()
108
178
  script_path = (
109
179
  "/wxoLoader.js?embed=true"
110
180
  if is_local
111
181
  else "/wxochat/wxoLoader.js?embed=true"
112
182
  )
113
183
 
184
+ config_lines = [
185
+ f'orchestrationID: "{tenant_id}"',
186
+ f'hostURL: "{host_url}"',
187
+ 'rootElementID: "root"',
188
+ 'showLauncher: true',
189
+ ]
190
+
191
+ # Conditional fields for IBM Cloud
192
+ if is_ibm_cloud_env:
193
+ config_lines.append(f'crn: "{crn}"')
194
+ if is_ibm_cloud_env:
195
+ config_lines.append(f'deploymentPlatform: "ibmcloud"')
196
+
197
+ config_lines.append(f"""chatOptions: {{
198
+ agentId: "{agent_id}",
199
+ agentEnvironmentId: "{agent_env_id}"
200
+ }}""")
201
+
202
+ config_body = ",\n ".join(config_lines)
203
+
114
204
  script = f"""
115
205
  <script>
116
206
  window.wxOConfiguration = {{
117
- orchestrationID: "{tenant_id}",
118
- hostURL: "{host_url}",
119
- rootElementID: "root",
120
- showLauncher: true,
121
- chatOptions: {{
122
- agentId: "{agent_id}",
123
- agentEnvironmentId: "{agent_env_id}"
124
- }},
207
+ {config_body}
125
208
  }};
126
209
 
127
210
  setTimeout(function () {{
128
211
  const script = document.createElement('script');
129
212
  script.src = `${{window.wxOConfiguration.hostURL}}{script_path}`;
130
213
  script.addEventListener('load', function () {{
131
- wxoLoader.init();
214
+ wxoLoader.init();
132
215
  }});
133
216
  document.head.appendChild(script);
134
217
  }}, 0);
135
218
  </script>
136
- """
219
+ """
137
220
 
138
221
  rich.print(script)
139
222
  return script
@@ -24,6 +24,8 @@ def chat_start(
24
24
  url = "http://localhost:3000/chat-lite"
25
25
  webbrowser.open(url)
26
26
  logger.info(f"Opening chat interface at {url}")
27
+ # TODO: Remove when connections UI is added
28
+ logger.warning("When using local chat, requests that the user 'Connect Apps' must be resolved by running `orchestrate connections set-credentials`")
27
29
  else:
28
30
  logger.error("Unable to start orchestrate UI chat service. Please check error messages and logs")
29
31
 
@@ -191,31 +191,31 @@ def set_credentials_connection_command(
191
191
  typer.Option(
192
192
  '--client-id',
193
193
  # help='For oauth_auth_on_behalf_of_flow, oauth_auth_code_flow, oauth_auth_implicit_flow, oauth_auth_password_flow and oauth_auth_client_credentials_flow, the client_id to authenticate against the application token server'
194
- help='For oauth_auth_on_behalf_of_flow, the client_id to authenticate against the application token server'
194
+ help='For oauth_auth_on_behalf_of_flow and oauth_auth_client_credentials_flow, the client_id to authenticate against the application token server'
195
+ )
196
+ ] = None,
197
+ client_secret: Annotated[
198
+ str,
199
+ typer.Option(
200
+ '--client-secret',
201
+ help='For oauth_auth_client_credentials_flow, the client_secret to authenticate with'
195
202
  )
196
203
  ] = None,
197
- # client_secret: Annotated[
198
- # str,
199
- # typer.Option(
200
- # '--client-secret',
201
- # help='For oauth_auth_code_flow, oauth_auth_password_flow and oauth_auth_client_credentials_flow, the client_secret to authenticate with'
202
- # )
203
- # ] = None,
204
204
  token_url: Annotated[
205
205
  str,
206
206
  typer.Option(
207
207
  '--token-url',
208
208
  # help='For oauth_auth_on_behalf_of_flow, oauth_auth_code_flow, oauth_auth_password_flow and oauth_auth_client_credentials_flow, the url of the application token server'
209
- help='For oauth_auth_on_behalf_of_flow, the url of the application token server'
209
+ help='For oauth_auth_on_behalf_of_flow and oauth_auth_client_credentials_flow, the url of the application token server'
210
+ )
211
+ ] = None,
212
+ auth_url: Annotated[
213
+ str,
214
+ typer.Option(
215
+ '--auth-url',
216
+ help='For oauth_auth_code_flow, the url of the application token server'
210
217
  )
211
218
  ] = None,
212
- # auth_url: Annotated[
213
- # str,
214
- # typer.Option(
215
- # '--auth-url',
216
- # help='For oauth_auth_code_flow, oauth_auth_implicit_flow and oauth_auth_password_flow, the url of the application token server'
217
- # )
218
- # ] = None,
219
219
  grant_type: Annotated[
220
220
  str,
221
221
  typer.Option(
@@ -223,6 +223,13 @@ def set_credentials_connection_command(
223
223
  help='For oauth_auth_on_behalf_of_flow, the grant type used by the application token server'
224
224
  )
225
225
  ] = None,
226
+ scopes: Annotated[
227
+ List[str],
228
+ typer.Option(
229
+ '--scopes',
230
+ help='For oauth_auth_code_flow and oauth_auth_client_credentials_flow, the optional scopes used by the application token server'
231
+ )
232
+ ] = None,
226
233
  entries: Annotated[
227
234
  List[str],
228
235
  typer.Option(
@@ -239,10 +246,11 @@ def set_credentials_connection_command(
239
246
  token=token,
240
247
  api_key=api_key,
241
248
  client_id=client_id,
242
- # client_secret=client_secret,
249
+ client_secret=client_secret,
243
250
  token_url=token_url,
244
- # auth_url=auth_url,
251
+ auth_url=auth_url,
245
252
  grant_type=grant_type,
253
+ scopes=scopes,
246
254
  entries=entries
247
255
  )
248
256
 
@@ -15,19 +15,19 @@ from ibm_watsonx_orchestrate.agent_builder.connections.types import (
15
15
  ConnectionType,
16
16
  IdpConfigData,
17
17
  IdpConfigDataBody,
18
- AppConfigData,
18
+ AppConfigData,
19
19
  BasicAuthCredentials,
20
20
  BearerTokenAuthCredentials,
21
21
  APIKeyAuthCredentials,
22
22
  # OAuth2AuthCodeCredentials,
23
- # OAuth2ClientCredentials,
23
+ OAuth2ClientCredentials,
24
24
  # OAuth2ImplicitCredentials,
25
25
  # OAuth2PasswordCredentials,
26
26
  OAuthOnBehalfOfCredentials,
27
27
  KeyValueConnectionCredentials,
28
28
  CREDENTIALS,
29
29
  IdentityProviderCredentials,
30
- OAUTH_CONNECTION_TYPES
30
+ OAUTH_CONNECTION_TYPES, OAuth2AuthCodeCredentials
31
31
 
32
32
  )
33
33
 
@@ -136,40 +136,31 @@ def _validate_connection_params(type: ConnectionType, **args) -> None:
136
136
  f"Missing flags --api-key is required for type {type}"
137
137
  )
138
138
 
139
- # if type in OAUTH_CONNECTION_TYPES and args.get('client_id') is None:
140
- # raise typer.BadParameter(
141
- # f"Missing flags --client-id is required for type {type}"
142
- # )
143
-
144
- # if type in (OAUTH_CONNECTION_TYPES.difference({ConnectionType.OAUTH2_IMPLICIT, ConnectionType.OAUTH_ON_BEHALF_OF_FLOW})) and args.get('client_secret') is None:
145
- # raise typer.BadParameter(
146
- # f"Missing flags --client-secret is required for type {type}"
147
- # )
148
-
149
- # if type in (OAUTH_CONNECTION_TYPES.difference({ConnectionType.OAUTH2_IMPLICIT})) and args.get('token_url') is None:
150
- # raise typer.BadParameter(
151
- # f"Missing flags --token-url is required for type {type}"
152
- # )
139
+ if type in {ConnectionType.OAUTH2_CLIENT_CREDS, ConnectionType.OAUTH2_AUTH_CODE} and args.get('client_secret') is None:
140
+ raise typer.BadParameter(
141
+ f"Missing flags --client-secret is required for type {type}"
142
+ )
153
143
 
154
- # if type in (OAUTH_CONNECTION_TYPES.difference({ConnectionType.OAUTH2_CLIENT_CREDS, ConnectionType.OAUTH_ON_BEHALF_OF_FLOW})) and args.get('auth_url') is None:
155
- # raise typer.BadParameter(
156
- # f"Missing flags --auth-url is required for type {type}"
157
- # )
144
+ if type in {ConnectionType.OAUTH2_AUTH_CODE} and args.get('auth_url') is None:
145
+ raise typer.BadParameter(
146
+ f"Missing flags --auth-url is required for type {type}"
147
+ )
158
148
 
159
- if type == ConnectionType.OAUTH_ON_BEHALF_OF_FLOW and (
149
+ if type in {ConnectionType.OAUTH_ON_BEHALF_OF_FLOW, ConnectionType.OAUTH2_CLIENT_CREDS, ConnectionType.OAUTH2_AUTH_CODE} and (
160
150
  args.get('client_id') is None
161
151
  ):
162
152
  raise typer.BadParameter(
163
153
  f"Missing flags --client-id is required for type {type}"
164
154
  )
165
155
 
166
- if type == ConnectionType.OAUTH_ON_BEHALF_OF_FLOW and (
156
+ if type in {ConnectionType.OAUTH_ON_BEHALF_OF_FLOW, ConnectionType.OAUTH2_CLIENT_CREDS, ConnectionType.OAUTH2_AUTH_CODE} and (
167
157
  args.get('token_url') is None
168
158
  ):
169
159
  raise typer.BadParameter(
170
160
  f"Missing flags --token-url is required for type {type}"
171
161
  )
172
162
 
163
+
173
164
  if type == ConnectionType.OAUTH_ON_BEHALF_OF_FLOW and (
174
165
  args.get('grant_type') is None
175
166
  ):
@@ -200,19 +191,21 @@ def _get_credentials(type: ConnectionType, **kwargs):
200
191
  return APIKeyAuthCredentials(
201
192
  api_key=kwargs.get("api_key")
202
193
  )
203
- # case ConnectionType.OAUTH2_AUTH_CODE:
204
- # return OAuth2AuthCodeCredentials(
205
- # authorization_url=kwargs.get("auth_url"),
206
- # client_id=kwargs.get("client_id"),
207
- # client_secret=kwargs.get("client_secret"),
208
- # token_url=kwargs.get("token_url")
209
- # )
210
- # case ConnectionType.OAUTH2_CLIENT_CREDS:
211
- # return OAuth2ClientCredentials(
212
- # client_id=kwargs.get("client_id"),
213
- # client_secret=kwargs.get("client_secret"),
214
- # token_url=kwargs.get("token_url")
215
- # )
194
+ case ConnectionType.OAUTH2_AUTH_CODE:
195
+ return OAuth2AuthCodeCredentials(
196
+ authorization_url=kwargs.get("auth_url"),
197
+ client_id=kwargs.get("client_id"),
198
+ client_secret=kwargs.get("client_secret"),
199
+ token_url=kwargs.get("token_url"),
200
+ scopes=kwargs.get("scopes")
201
+ )
202
+ case ConnectionType.OAUTH2_CLIENT_CREDS:
203
+ return OAuth2ClientCredentials(
204
+ client_id=kwargs.get("client_id"),
205
+ client_secret=kwargs.get("client_secret"),
206
+ token_url=kwargs.get("token_url"),
207
+ scopes=kwargs.get("scopes")
208
+ )
216
209
  # case ConnectionType.OAUTH2_IMPLICIT:
217
210
  # return OAuth2ImplicitCredentials(
218
211
  # authorization_url=kwargs.get("auth_url"),
@@ -267,11 +260,14 @@ def add_configuration(config: ConnectionConfiguration) -> None:
267
260
  logger.warning(f"Detected a change in sso from '{existing_configuration.sso}' to '{config.sso}'. The associated credentials will be removed.")
268
261
  should_delete_credentials = True
269
262
 
263
+ existing_conn_type = get_connection_type(security_scheme=existing_configuration.security_scheme, auth_type=existing_configuration.auth_type)
264
+ use_app_credentials = existing_conn_type in OAUTH_CONNECTION_TYPES
265
+
270
266
  if should_delete_credentials:
271
267
  try:
272
- existing_credentials = client.get_credentials(app_id=app_id, env=environment, use_sso=existing_configuration.sso)
268
+ existing_credentials = client.get_credentials(app_id=app_id, env=environment, use_app_credentials=use_app_credentials)
273
269
  if existing_credentials:
274
- client.delete_credentials(app_id=app_id, env=environment, use_sso=existing_configuration.sso)
270
+ client.delete_credentials(app_id=app_id, env=environment, use_app_credentials=use_app_credentials)
275
271
  except:
276
272
  logger.error(f"Error removing credentials for connection '{app_id}' in environment '{environment}'. No changes have been made to the configuration.")
277
273
  sys.exit(1)
@@ -289,11 +285,11 @@ def add_configuration(config: ConnectionConfiguration) -> None:
289
285
  logger.error(response_text)
290
286
  exit(1)
291
287
 
292
- def add_credentials(app_id: str, environment: ConnectionEnvironment, use_sso: bool, credentials: CREDENTIALS) -> None:
288
+ def add_credentials(app_id: str, environment: ConnectionEnvironment, use_app_credentials: bool, credentials: CREDENTIALS) -> None:
293
289
  client = get_connections_client()
294
290
  try:
295
- existing_credentials = client.get_credentials(app_id=app_id, env=environment, use_sso=use_sso)
296
- if use_sso:
291
+ existing_credentials = client.get_credentials(app_id=app_id, env=environment, use_app_credentials=use_app_credentials)
292
+ if use_app_credentials:
297
293
  payload = {
298
294
  "app_credentials": credentials.model_dump(exclude_none=True)
299
295
  }
@@ -304,9 +300,9 @@ def add_credentials(app_id: str, environment: ConnectionEnvironment, use_sso: bo
304
300
 
305
301
  logger.info(f"Setting credentials for environment '{environment}' on connection '{app_id}'")
306
302
  if existing_credentials:
307
- client.update_credentials(app_id=app_id, env=environment, use_sso=use_sso, payload=payload)
303
+ client.update_credentials(app_id=app_id, env=environment, use_app_credentials=use_app_credentials, payload=payload)
308
304
  else:
309
- client.create_credentials(app_id=app_id,env=environment, use_sso=use_sso, payload=payload)
305
+ client.create_credentials(app_id=app_id,env=environment, use_app_credentials=use_app_credentials, payload=payload)
310
306
  logger.info(f"Credentials successfully set for '{environment}' environment of connection '{app_id}'")
311
307
  except requests.HTTPError as e:
312
308
  response = e.response
@@ -318,7 +314,7 @@ def add_identity_provider(app_id: str, environment: ConnectionEnvironment, idp:
318
314
  client = get_connections_client()
319
315
 
320
316
  try:
321
- existing_credentials = client.get_credentials(app_id=app_id, env=environment, use_sso=True)
317
+ existing_credentials = client.get_credentials(app_id=app_id, env=environment, use_app_credentials=True)
322
318
 
323
319
  payload = {
324
320
  "idp_credentials": idp.model_dump()
@@ -326,9 +322,9 @@ def add_identity_provider(app_id: str, environment: ConnectionEnvironment, idp:
326
322
 
327
323
  logger.info(f"Setting identity provider for environment '{environment}' on connection '{app_id}'")
328
324
  if existing_credentials:
329
- client.update_credentials(app_id=app_id, env=environment, use_sso=True, payload=payload)
325
+ client.update_credentials(app_id=app_id, env=environment, use_app_credentials=True, payload=payload)
330
326
  else:
331
- client.create_credentials(app_id=app_id,env=environment, use_sso=True, payload=payload)
327
+ client.create_credentials(app_id=app_id,env=environment, use_app_credentials=True, payload=payload)
332
328
  logger.info(f"Identity provider successfully set for '{environment}' environment of connection '{app_id}'")
333
329
  except requests.HTTPError as e:
334
330
  response = e.response
@@ -350,7 +346,7 @@ def add_connection(app_id: str) -> None:
350
346
  status_code = response.status_code
351
347
  try:
352
348
  if status_code == 409:
353
- response_text = f"Failed to create connection. A connection with the App ID '{app_id}' already exists. Please select a diffrent App ID or delete the existing resource."
349
+ response_text = f"Failed to create connection. A connection with the App ID '{app_id}' already exists. Please select a different App ID or delete the existing resource."
354
350
  else:
355
351
  resp = json.loads(response_text)
356
352
  response_text = resp.get('detail')
@@ -374,12 +370,14 @@ def remove_connection(app_id: str) -> None:
374
370
 
375
371
  def list_connections(environment: ConnectionEnvironment | None, verbose: bool = False) -> None:
376
372
  client = get_connections_client()
377
-
378
373
  connections = client.list()
379
-
374
+ is_local = is_local_dev()
375
+
380
376
  if verbose:
381
377
  connections_list = []
382
378
  for conn in connections:
379
+ if is_local and conn.environment == ConnectionEnvironment.LIVE:
380
+ continue
383
381
  connections_list.append(json.loads(conn.model_dump_json()))
384
382
 
385
383
  rich.print_json(json.dumps(connections_list, indent=4))
@@ -387,11 +385,17 @@ def list_connections(environment: ConnectionEnvironment | None, verbose: bool =
387
385
  non_configured_table = rich.table.Table(show_header=True, header_style="bold white", show_lines=True, title="*Non-Configured")
388
386
  draft_table = rich.table.Table(show_header=True, header_style="bold white", show_lines=True, title="Draft")
389
387
  live_table = rich.table.Table(show_header=True, header_style="bold white", show_lines=True, title="Live")
390
- columns = ["App ID", "Auth Type", "Type", "Credentials Set"]
391
- for column in columns:
392
- draft_table.add_column(column, justify='center', no_wrap=True)
393
- live_table.add_column(column, justify='center', no_wrap=True)
394
- non_configured_table.add_column(column, justify='center', no_wrap=True)
388
+ default_args = {"justify": "center", "no_wrap": True}
389
+ column_args = {
390
+ "App ID": {"overflow": "fold"},
391
+ "Auth Type": {},
392
+ "Type": {},
393
+ "Credentials Set/ Connected": {}
394
+ }
395
+ for column in column_args:
396
+ draft_table.add_column(column,**default_args, **column_args[column])
397
+ live_table.add_column(column,**default_args, **column_args[column])
398
+ non_configured_table.add_column(column,**default_args, **column_args[column])
395
399
 
396
400
  for conn in connections:
397
401
  if conn.environment is None:
@@ -412,7 +416,7 @@ def list_connections(environment: ConnectionEnvironment | None, verbose: bool =
412
416
  conn.preference,
413
417
  "✅" if conn.credentials_entered else "❌"
414
418
  )
415
- elif conn.environment == ConnectionEnvironment.LIVE:
419
+ elif conn.environment == ConnectionEnvironment.LIVE and not is_local:
416
420
  live_table.add_row(
417
421
  conn.app_id,
418
422
  connection_type,
@@ -463,11 +467,6 @@ def configure_connection(**kwargs) -> None:
463
467
 
464
468
  config = ConnectionConfiguration.model_validate(kwargs)
465
469
 
466
- # TODO: Remove once Oauth is supported on local
467
- if config.security_scheme == ConnectionSecurityScheme.OAUTH2 and is_local_dev():
468
- logger.error("Use of OAuth connections unsupported for local development at this time.")
469
- sys.exit(1)
470
-
471
470
  add_configuration(config)
472
471
 
473
472
  def set_credentials_connection(
@@ -484,11 +483,12 @@ def set_credentials_connection(
484
483
 
485
484
  sso_enabled = config.sso
486
485
  conn_type = get_connection_type(security_scheme=config.security_scheme, auth_type=config.auth_type)
486
+ use_app_credentials = conn_type in OAUTH_CONNECTION_TYPES
487
487
 
488
488
  _validate_connection_params(type=conn_type, **kwargs)
489
489
  credentials = _get_credentials(type=conn_type, **kwargs)
490
490
 
491
- add_credentials(app_id=app_id, environment=environment, use_sso=sso_enabled, credentials=credentials)
491
+ add_credentials(app_id=app_id, environment=environment, use_app_credentials=use_app_credentials, credentials=credentials)
492
492
 
493
493
  def set_identity_provider_connection(
494
494
  app_id: str,
@@ -167,7 +167,7 @@ def activate(name: str, apikey: str=None, username: str=None, password: str=None
167
167
 
168
168
  def add(name: str, url: str, should_activate: bool=False, iam_url: str=None, type: EnvironmentAuthType=None, insecure: bool=None, verify: str=None) -> None:
169
169
  if name == PROTECTED_ENV_NAME:
170
- logger.error(f"The name '{PROTECTED_ENV_NAME}' is a reserved environment name. Please select a diffrent name or use `orchestrate env activate {PROTECTED_ENV_NAME}` to swap to '{PROTECTED_ENV_NAME}'")
170
+ logger.error(f"The name '{PROTECTED_ENV_NAME}' is a reserved environment name. Please select a different name or use `orchestrate env activate {PROTECTED_ENV_NAME}` to swap to '{PROTECTED_ENV_NAME}'")
171
171
  return
172
172
 
173
173
  cfg = Config()