ibm-watsonx-orchestrate 1.9.0b1__py3-none-any.whl → 1.10.0b0__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 (34) hide show
  1. ibm_watsonx_orchestrate/__init__.py +2 -1
  2. ibm_watsonx_orchestrate/agent_builder/agents/types.py +2 -0
  3. ibm_watsonx_orchestrate/agent_builder/knowledge_bases/types.py +2 -2
  4. ibm_watsonx_orchestrate/agent_builder/models/types.py +5 -0
  5. ibm_watsonx_orchestrate/agent_builder/tools/python_tool.py +19 -7
  6. ibm_watsonx_orchestrate/agent_builder/tools/types.py +5 -3
  7. ibm_watsonx_orchestrate/agent_builder/voice_configurations/__init__.py +1 -0
  8. ibm_watsonx_orchestrate/agent_builder/voice_configurations/types.py +98 -0
  9. ibm_watsonx_orchestrate/cli/commands/agents/agents_command.py +20 -0
  10. ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +170 -1
  11. ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +5 -2
  12. ibm_watsonx_orchestrate/cli/commands/copilot/copilot_controller.py +103 -20
  13. ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_controller.py +19 -12
  14. ibm_watsonx_orchestrate/cli/commands/models/model_provider_mapper.py +17 -13
  15. ibm_watsonx_orchestrate/cli/commands/server/server_command.py +17 -4
  16. ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +6 -1
  17. ibm_watsonx_orchestrate/cli/commands/voice_configurations/voice_configurations_command.py +58 -0
  18. ibm_watsonx_orchestrate/cli/commands/voice_configurations/voice_configurations_controller.py +173 -0
  19. ibm_watsonx_orchestrate/cli/main.py +2 -0
  20. ibm_watsonx_orchestrate/client/agents/agent_client.py +64 -1
  21. ibm_watsonx_orchestrate/client/connections/connections_client.py +14 -2
  22. ibm_watsonx_orchestrate/client/copilot/cpe/copilot_cpe_client.py +5 -3
  23. ibm_watsonx_orchestrate/client/voice_configurations/voice_configurations_client.py +75 -0
  24. ibm_watsonx_orchestrate/docker/compose-lite.yml +23 -2
  25. ibm_watsonx_orchestrate/docker/default.env +16 -12
  26. ibm_watsonx_orchestrate/flow_builder/flows/__init__.py +2 -2
  27. ibm_watsonx_orchestrate/flow_builder/flows/flow.py +29 -24
  28. ibm_watsonx_orchestrate/flow_builder/types.py +109 -17
  29. ibm_watsonx_orchestrate/flow_builder/utils.py +7 -3
  30. {ibm_watsonx_orchestrate-1.9.0b1.dist-info → ibm_watsonx_orchestrate-1.10.0b0.dist-info}/METADATA +1 -1
  31. {ibm_watsonx_orchestrate-1.9.0b1.dist-info → ibm_watsonx_orchestrate-1.10.0b0.dist-info}/RECORD +34 -29
  32. {ibm_watsonx_orchestrate-1.9.0b1.dist-info → ibm_watsonx_orchestrate-1.10.0b0.dist-info}/WHEEL +0 -0
  33. {ibm_watsonx_orchestrate-1.9.0b1.dist-info → ibm_watsonx_orchestrate-1.10.0b0.dist-info}/entry_points.txt +0 -0
  34. {ibm_watsonx_orchestrate-1.9.0b1.dist-info → ibm_watsonx_orchestrate-1.10.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -5,7 +5,8 @@
5
5
 
6
6
  pkg_name = "ibm-watsonx-orchestrate"
7
7
 
8
- __version__ = "1.9.0b1"
8
+ __version__ = "1.10.0b0"
9
+
9
10
 
10
11
 
11
12
 
@@ -77,6 +77,8 @@ class BaseAgentSpec(BaseModel):
77
77
  description: Annotated[str, Field(json_schema_extra={"min_length_str":1})]
78
78
  context_access_enabled: bool = True
79
79
  context_variables: Optional[List[str]] = []
80
+ voice_configuration_id: Optional[str] = None
81
+ voice_configuration: Optional[str] = None
80
82
 
81
83
  def dump_spec(self, file: str) -> None:
82
84
  dumped = self.model_dump(mode='json', exclude_unset=True, exclude_none=True)
@@ -86,11 +86,10 @@ class GenerationConfiguration(BaseModel):
86
86
  {
87
87
  "model_id": "meta-llama/llama-3-1-70b-instruct",
88
88
  "prompt_instruction": "When the documents are in different languages, you should respond in english.",
89
- "retrieval_confidence_threshold": "Lowest",
90
89
  "generated_response_length": "Moderate",
91
- "response_confidence_threshold": "Low",
92
90
  "display_text_no_results_found": "no docs found",
93
91
  "display_text_connectivity_issue": "conn failed",
92
+ "idk_message": "I dont know",
94
93
  }
95
94
  """
96
95
 
@@ -99,6 +98,7 @@ class GenerationConfiguration(BaseModel):
99
98
  generated_response_length: Optional[GeneratedResponseLength] = None
100
99
  display_text_no_results_found: Optional[str] = None
101
100
  display_text_connectivity_issue: Optional[str] = None
101
+ idk_message: Optional[str] = None
102
102
 
103
103
  class FieldMapping(BaseModel):
104
104
  """
@@ -87,6 +87,11 @@ class ProviderConfig(BaseModel):
87
87
  azure_entra_tenant_id: Optional[str] = Field(None, alias="azureEntraTenantId")
88
88
  azure_ad_token: Optional[str] = Field(None, alias="azureAdToken")
89
89
  azure_model_name: Optional[str] = Field(None, alias="azureModelName")
90
+ azure_inference_deployment_name: Optional[str] = Field(None, alias="azureDeploymentName")
91
+ azure_inference_api_version: Optional[str] = Field(None, alias="azureApiVersion")
92
+ azure_inference_extra_params: Optional[str] = Field(None, alias="azureExtraParams")
93
+ azure_inference_foundry_url: Optional[str] = Field(None, alias="azureFoundryUrl")
94
+
90
95
 
91
96
  # Workers AI specific
92
97
  workers_ai_account_id: Optional[str] = Field(None, alias="workersAiAccountId")
@@ -187,15 +187,27 @@ def _fix_optional(schema):
187
187
  replacements = {}
188
188
  if schema.required is None:
189
189
  schema.required = []
190
-
191
190
  for k, v in schema.properties.items():
191
+ # Simple null type & required -> not required
192
192
  if v.type == 'null' and k in schema.required:
193
193
  not_required.append(k)
194
- if v.anyOf is not None and next(filter(lambda x: x.type == 'null', v.anyOf)) and k in schema.required:
195
- v.anyOf = list(filter(lambda x: x.type != 'null', v.anyOf))
196
- if len(v.anyOf) == 1:
197
- replacements[k] = v.anyOf[0]
198
- not_required.append(k)
194
+ # Optional with null & required
195
+ if v.anyOf is not None and [x for x in v.anyOf if x.type == 'null']:
196
+ if k in schema.required:
197
+ # required with default -> not required
198
+ # required without default -> required & remove null from union
199
+ if v.default:
200
+ not_required.append(k)
201
+ else:
202
+ v.anyOf = list(filter(lambda x: x.type != 'null', v.anyOf))
203
+ if len(v.anyOf) == 1:
204
+ replacements[k] = v.anyOf[0]
205
+ else:
206
+ # not required with default -> no change
207
+ # not required without default -> means default input is 'None'
208
+ v.default = v.default if v.default else 'null'
209
+
210
+
199
211
  schema.required = list(filter(lambda x: x not in not_required, schema.required if schema.required is not None else []))
200
212
  for k, v in replacements.items():
201
213
  combined = {
@@ -204,7 +216,7 @@ def _fix_optional(schema):
204
216
  }
205
217
  schema.properties[k] = JsonSchemaObject(**combined)
206
218
  schema.properties[k].anyOf = None
207
-
219
+
208
220
  for k in schema.properties.keys():
209
221
  if schema.properties[k].type == 'object':
210
222
  schema.properties[k] = _fix_optional(schema.properties[k])
@@ -36,6 +36,7 @@ class JsonSchemaObject(BaseModel):
36
36
  anyOf: Optional[List['JsonSchemaObject']] = None
37
37
  in_field: Optional[Literal['query', 'header', 'path', 'body']] = Field(None, alias='in')
38
38
  aliasName: str | None = None
39
+ wrap_data: Optional[bool] = True
39
40
  "Runtime feature where the sdk can provide the original name of a field before prefixing"
40
41
 
41
42
  @model_validator(mode='after')
@@ -48,9 +49,9 @@ class JsonSchemaObject(BaseModel):
48
49
  class ToolRequestBody(BaseModel):
49
50
  model_config = ConfigDict(extra='allow')
50
51
 
51
- type: Literal['object']
52
- properties: Dict[str, JsonSchemaObject]
53
- required: Optional[List[str]] = None
52
+ type: Literal['object', 'string']
53
+ properties: Optional[Dict[str, JsonSchemaObject]] = {}
54
+ required: Optional[List[str]] = []
54
55
 
55
56
 
56
57
  class ToolResponseBody(BaseModel):
@@ -186,6 +187,7 @@ class ToolBinding(BaseModel):
186
187
 
187
188
  class ToolSpec(BaseModel):
188
189
  name: str
190
+ id: str | None = None
189
191
  display_name: str | None = None
190
192
  description: str
191
193
  permission: ToolPermission
@@ -0,0 +1 @@
1
+ from .types import VoiceConfiguration
@@ -0,0 +1,98 @@
1
+ import json
2
+ from typing import Annotated, Optional, List, Dict
3
+ from pydantic import BaseModel, Field, model_validator
4
+
5
+ def _validate_exactly_one_of_fields(object: BaseModel, object_name: str, fields: list[str]):
6
+ present_fields = [getattr(object,field) for field in fields if getattr(object,field) is not None]
7
+
8
+ if len(present_fields) != 1:
9
+ raise ValueError(f"{object_name} requires exactly one of {','.join(fields)}")
10
+
11
+
12
+ def _validate_language_uniqueness(config: BaseModel):
13
+ if hasattr(config,'language') and hasattr(config,'additional_languages'):
14
+ if config.language and config.additional_languages and config.language in config.additional_languages:
15
+ raise ValueError(f"Language '{config.language}' cannot be in both the default language and additional_languages")
16
+
17
+
18
+ class WatsonSTTConfig(BaseModel):
19
+ api_url: Annotated[str, Field(min_length=1,max_length=2048)]
20
+ api_key: Optional[Annotated[str, Field(min_length=1,max_length=2048)]] = None
21
+ bearer_token: Optional[Annotated[str, Field(min_length=1,max_length=2048)]] = None
22
+ model: Annotated[str, Field(min_length=1,max_length=256)]
23
+
24
+ class EmotechSTTConfig(BaseModel):
25
+ api_key: Annotated[str,Field(min_length=1,max_length=2048)]
26
+ api_url: Annotated[str,Field(min_length=1,max_length=2048)]
27
+
28
+
29
+ class SpeechToTextConfig(BaseModel):
30
+ provider: Annotated[str, Field(min_length=1,max_length=128)]
31
+ watson_stt_config: Optional[WatsonSTTConfig] = None
32
+ emotech_stt_config: Optional[EmotechSTTConfig] = None
33
+
34
+ @model_validator(mode='after')
35
+ def validate_providers(self):
36
+ _validate_exactly_one_of_fields(self,'SpeechToTextConfig',['watson_stt_config','emotech_stt_config'])
37
+ return self
38
+
39
+ class WatsonTTSConfig(BaseModel):
40
+ api_url: Annotated[str, Field(min_length=1,max_length=2048)]
41
+ api_key: Optional[Annotated[str, Field(min_length=1,max_length=2048)]] = None
42
+ bearer_token: Optional[Annotated[str, Field(min_length=1,max_length=2048)]] = None
43
+ voice: Annotated[str, Field(min_length=1,max_length=128)]
44
+ rate_percentage: Optional[int] = None
45
+ pitch_percentage: Optional[int] = None
46
+ language: Optional[str] = None
47
+
48
+ class EmotechTTSConfig(BaseModel):
49
+ api_url: Annotated[str, Field(min_length=1,max_length=2048)]
50
+ api_key: Annotated[str, Field(min_length=1,max_length=2048)]
51
+ voice: Optional[Annotated[str, Field(min_length=1,max_length=128)]]
52
+
53
+ class TextToSpeechConfig(BaseModel):
54
+ provider: Annotated[str, Field(min_length=1,max_length=128)]
55
+ watson_tts_config: Optional[WatsonTTSConfig] = None
56
+ emotech_tts_config: Optional[EmotechTTSConfig] = None
57
+
58
+ @model_validator(mode='after')
59
+ def validate_providers(self):
60
+ _validate_exactly_one_of_fields(self,'TextToSpeechConfig',['watson_tts_config','emotech_tts_config'])
61
+ return self
62
+
63
+ class AdditionalProperties(BaseModel):
64
+ speech_to_text: Optional[SpeechToTextConfig] = None
65
+ text_to_speech: Optional[TextToSpeechConfig] = None
66
+
67
+ class DTMFInput(BaseModel):
68
+ inter_digit_timeout_ms: Optional[int] = None
69
+ termination_key: Optional[str] = None
70
+ maximum_count: Optional[int] = None
71
+ ignore_speech: Optional[bool] = None
72
+
73
+ class AttachedAgent(BaseModel):
74
+ id: str
75
+ name: Optional[str] = None
76
+ display_name: Optional[str] = None
77
+
78
+ class VoiceConfiguration(BaseModel):
79
+ name: Annotated[str, Field(min_length=1,max_length=128)]
80
+ speech_to_text: SpeechToTextConfig
81
+ text_to_speech: TextToSpeechConfig
82
+ language: Optional[Annotated[str,Field(min_length=2,max_length=16)]] = None
83
+ additional_languages: Optional[dict[str,AdditionalProperties]] = None
84
+ dtmf_input: Optional[DTMFInput] = None
85
+ voice_configuration_id: Optional[str] = None
86
+ tenant_id: Optional[Annotated[str, Field(min_length=1,max_length=128)]] = None
87
+ attached_agents: Optional[list[AttachedAgent]] = None
88
+
89
+ @model_validator(mode='after')
90
+ def validate_language(self):
91
+ _validate_language_uniqueness(self)
92
+ return self
93
+
94
+ def dumps_spec(self) -> str:
95
+ dumped = self.model_dump(mode='json', exclude_none=True)
96
+ return json.dumps(dumped, indent=2)
97
+
98
+
@@ -253,3 +253,23 @@ def export_agent(
253
253
  ):
254
254
  agents_controller = AgentsController()
255
255
  agents_controller.export_agent(name=name, kind=kind, output_path=output_file, agent_only_flag=agent_only_flag)
256
+
257
+ @agents_app.command(name="deploy", help="Deploy Agent")
258
+ def deploy_agent(
259
+ name: Annotated[
260
+ str,
261
+ typer.Option("--name", "-n", help="Name of the agent you wish to deploy"),
262
+ ]
263
+ ):
264
+ agents_controller = AgentsController()
265
+ agents_controller.deploy_agent(name=name)
266
+
267
+ @agents_app.command(name="undeploy", help="Undeploy Agent")
268
+ def undeploy_agent(
269
+ name: Annotated[
270
+ str,
271
+ typer.Option("--name", "-n", help="Name of the agent you wish to undeploy"),
272
+ ]
273
+ ):
274
+ agents_controller = AgentsController()
275
+ agents_controller.undeploy_agent(name=name)
@@ -29,13 +29,17 @@ from ibm_watsonx_orchestrate.client.agents.agent_client import AgentClient, Agen
29
29
  from ibm_watsonx_orchestrate.client.agents.external_agent_client import ExternalAgentClient
30
30
  from ibm_watsonx_orchestrate.client.agents.assistant_agent_client import AssistantAgentClient
31
31
  from ibm_watsonx_orchestrate.client.tools.tool_client import ToolClient
32
+ from ibm_watsonx_orchestrate.client.voice_configurations.voice_configurations_client import VoiceConfigurationsClient
32
33
  from ibm_watsonx_orchestrate.utils.exceptions import BadRequest
33
34
  from ibm_watsonx_orchestrate.client.connections import get_connections_client
34
35
  from ibm_watsonx_orchestrate.client.knowledge_bases.knowledge_base_client import KnowledgeBaseClient
35
36
 
36
- from ibm_watsonx_orchestrate.client.utils import instantiate_client
37
+ from ibm_watsonx_orchestrate.client.utils import instantiate_client, is_local_dev
37
38
  from ibm_watsonx_orchestrate.utils.utils import check_file_in_zip
38
39
 
40
+ from rich.console import Console
41
+ from rich.progress import Progress, SpinnerColumn, TextColumn
42
+
39
43
  logger = logging.getLogger(__name__)
40
44
 
41
45
  # Helper generic type for any agent
@@ -197,6 +201,7 @@ def get_app_id_from_conn_id(conn_id: str) -> str:
197
201
  exit(1)
198
202
  return app_id
199
203
 
204
+
200
205
  def get_agent_details(name: str, client: AgentClient | ExternalAgentClient | AssistantAgentClient) -> dict:
201
206
  agent_specs = client.get_draft_by_name(name)
202
207
  if len(agent_specs) > 1:
@@ -219,6 +224,7 @@ class AgentsController:
219
224
  self.assistant_client = None
220
225
  self.tool_client = None
221
226
  self.knowledge_base_client = None
227
+ self.voice_configuration_client = None
222
228
 
223
229
  def get_native_client(self):
224
230
  if not self.native_client:
@@ -245,6 +251,11 @@ class AgentsController:
245
251
  self.knowledge_base_client = instantiate_client(KnowledgeBaseClient)
246
252
  return self.knowledge_base_client
247
253
 
254
+ def get_voice_configuration_client(self):
255
+ if not self.voice_configuration_client:
256
+ self.voice_configuration_client = instantiate_client(VoiceConfigurationsClient)
257
+ return self.voice_configuration_client
258
+
248
259
  @staticmethod
249
260
  def import_agent(file: str, app_id: str) -> List[Agent | ExternalAgent | AssistantAgent]:
250
261
  agents = parse_file(file)
@@ -520,6 +531,38 @@ class AgentsController:
520
531
  guideline.tool = name
521
532
 
522
533
  return ref_agent
534
+
535
+ def get_voice_config_name_from_id(self, voice_config_id: str) -> str | None:
536
+ client = self.get_voice_configuration_client()
537
+ config = client.get_by_id(voice_config_id)
538
+ return config.name if config else None
539
+
540
+ def get_voice_config_id_from_name(self, voice_config_name: str) -> str | None:
541
+ client = self.get_voice_configuration_client()
542
+ configs = client.get_by_name(voice_config_name)
543
+
544
+ if len(configs) == 0:
545
+ logger.error(f"No voice_configs with the name '{voice_config_name}' found. Failed to get config")
546
+ sys.exit(1)
547
+
548
+ if len(configs) > 1:
549
+ logger.error(f"Multiple voice_configs with the name '{voice_config_name}' found. Failed to get config")
550
+ sys.exit(1)
551
+
552
+ return configs[0].voice_configuration_id
553
+
554
+
555
+ def reference_voice_config(self,agent: Agent):
556
+ deref_agent = deepcopy(agent)
557
+ deref_agent.voice_configuration = self.get_voice_config_name_from_id(agent.voice_configuration_id)
558
+ del deref_agent.voice_configuration_id
559
+ return deref_agent
560
+
561
+ def dereference_voice_config(self,agent: Agent):
562
+ ref_agent = deepcopy(agent)
563
+ ref_agent.voice_configuration_id = self.get_voice_config_id_from_name(agent.voice_configuration)
564
+ del ref_agent.voice_configuration
565
+ return ref_agent
523
566
 
524
567
  @staticmethod
525
568
  def dereference_app_id(agent: ExternalAgent | AssistantAgent) -> ExternalAgent | AssistantAgent:
@@ -540,7 +583,18 @@ class AgentsController:
540
583
  agent.config.connection_id = None
541
584
 
542
585
  return agent
586
+
587
+ def dereference_common_agent_dependencies(self, agent: AnyAgentT) -> AnyAgentT:
588
+ if agent.voice_configuration:
589
+ agent = self.dereference_voice_config(agent)
590
+
591
+ return agent
592
+
593
+ def reference_common_agent_dependencies(self, agent: AnyAgentT) -> AnyAgentT:
594
+ if agent.voice_configuration_id:
595
+ agent = self.reference_voice_config(agent)
543
596
 
597
+ return agent
544
598
 
545
599
  def dereference_native_agent_dependencies(self, agent: Agent) -> Agent:
546
600
  if agent.collaborators and len(agent.collaborators):
@@ -584,6 +638,8 @@ class AgentsController:
584
638
 
585
639
  # Convert all names used in an agent to the corresponding ids
586
640
  def dereference_agent_dependencies(self, agent: AnyAgentT) -> AnyAgentT:
641
+
642
+ agent = self.dereference_common_agent_dependencies(agent)
587
643
  if isinstance(agent, Agent):
588
644
  return self.dereference_native_agent_dependencies(agent)
589
645
  if isinstance(agent, ExternalAgent) or isinstance(agent, AssistantAgent):
@@ -591,6 +647,8 @@ class AgentsController:
591
647
 
592
648
  # Convert all ids used in an agent to the corresponding names
593
649
  def reference_agent_dependencies(self, agent: AnyAgentT) -> AnyAgentT:
650
+
651
+ agent = self.reference_common_agent_dependencies(agent)
594
652
  if isinstance(agent, Agent):
595
653
  return self.reference_native_agent_dependencies(agent)
596
654
  if isinstance(agent, ExternalAgent) or isinstance(agent, AssistantAgent):
@@ -1111,3 +1169,114 @@ class AgentsController:
1111
1169
  logger.info(f"Successfully wrote agents and tools to '{output_path}'")
1112
1170
  zip_file_out.close()
1113
1171
 
1172
+
1173
+ def deploy_agent(self, name: str):
1174
+ if is_local_dev():
1175
+ logger.error("Agents cannot be deployed in Developer Edition")
1176
+ sys.exit(1)
1177
+ native_client = self.get_native_client()
1178
+ external_client = self.get_external_client()
1179
+ assistant_client = self.get_assistant_client()
1180
+
1181
+ existing_native_agents = native_client.get_draft_by_name(name)
1182
+ existing_external_agents = external_client.get_draft_by_name(name)
1183
+ existing_assistant_agents = assistant_client.get_draft_by_name(name)
1184
+
1185
+ if len(existing_native_agents) == 0 and (len(existing_external_agents) >= 1 or len(existing_assistant_agents) >= 1):
1186
+ logger.error(f"No native agent found with name '{name}'. Only Native Agents can be deployed to a Live Environment")
1187
+ sys.exit(1)
1188
+ if len(existing_native_agents) > 1:
1189
+ logger.error(f"Multiple native agents with the name '{name}' found. Failed to get agent")
1190
+ sys.exit(1)
1191
+ if len(existing_native_agents) == 0:
1192
+ logger.error(f"No native agents with the name '{name}' found. Failed to get agent")
1193
+ sys.exit(1)
1194
+
1195
+
1196
+ agent_details = existing_native_agents[0]
1197
+ agent_id = agent_details.get("id")
1198
+
1199
+ environments = native_client.get_environments_for_agent(agent_id)
1200
+
1201
+ live_environment = [env for env in environments if env.get("name") == "live"]
1202
+ if live_environment is None:
1203
+ logger.error("No live environment found for this tenant")
1204
+ sys.exit(1)
1205
+
1206
+ live_env_id = live_environment[0].get("id")
1207
+
1208
+ console = Console()
1209
+ with Progress(
1210
+ SpinnerColumn(spinner_name="dots"),
1211
+ TextColumn("[progress.description]{task.description}"),
1212
+ transient=True,
1213
+ console=console,
1214
+ ) as progress:
1215
+ progress.add_task(description="Deploying agent to Live envrionment", total=None)
1216
+
1217
+ status = native_client.deploy(agent_id, live_env_id)
1218
+
1219
+ if status:
1220
+ logger.info(f"Successfully deployed agent {name}")
1221
+ else:
1222
+ logger.error(f"Error deploying agent {name}")
1223
+
1224
+ def undeploy_agent(self, name: str):
1225
+ if is_local_dev():
1226
+ logger.error("Agents cannot be undeployed in Developer Edition")
1227
+ sys.exit(1)
1228
+
1229
+ native_client = self.get_native_client()
1230
+ external_client = self.get_external_client()
1231
+ assistant_client = self.get_assistant_client()
1232
+
1233
+ existing_native_agents = native_client.get_draft_by_name(name)
1234
+ existing_external_agents = external_client.get_draft_by_name(name)
1235
+ existing_assistant_agents = assistant_client.get_draft_by_name(name)
1236
+
1237
+ if len(existing_native_agents) == 0 and (len(existing_external_agents) >= 1 or len(existing_assistant_agents) >= 1):
1238
+ logger.error(f"No native agent found with name '{name}'. Only Native Agents can be undeployed from a Live Environment")
1239
+ sys.exit(1)
1240
+ if len(existing_native_agents) > 1:
1241
+ logger.error(f"Multiple native agents with the name '{name}' found. Failed to get agent")
1242
+ sys.exit(1)
1243
+ if len(existing_native_agents) == 0:
1244
+ logger.error(f"No native agents with the name '{name}' found. Failed to get agent")
1245
+ sys.exit(1)
1246
+
1247
+ agent_details = existing_native_agents[0]
1248
+ agent_id = agent_details.get("id")
1249
+
1250
+ environments = native_client.get_environments_for_agent(agent_id)
1251
+ live_environment = [env for env in environments if env.get("name") == "live"]
1252
+ if live_environment is None:
1253
+ logger.error("No live environment found for this tenant")
1254
+ sys.exit(1)
1255
+ version_id = live_environment[0].get("current_version")
1256
+
1257
+ if version_id is None:
1258
+ agent_name = agent_details.get("name")
1259
+ logger.error(f"Agent {agent_name} does not exist in a Live environment")
1260
+ sys.exit(1)
1261
+
1262
+ draft_environment = [env for env in environments if env.get("name") == "draft"]
1263
+ if draft_environment is None:
1264
+ logger.error("No draft environment found for this tenant")
1265
+ sys.exit(1)
1266
+ draft_env_id = draft_environment[0].get("id")
1267
+
1268
+ console = Console()
1269
+ with Progress(
1270
+ SpinnerColumn(spinner_name="dots"),
1271
+ TextColumn("[progress.description]{task.description}"),
1272
+ transient=True,
1273
+ console=console,
1274
+ ) as progress:
1275
+ progress.add_task(description="Undeploying agent to Draft envrionment", total=None)
1276
+
1277
+ status = native_client.undeploy(agent_id, version_id, draft_env_id)
1278
+ if status:
1279
+ logger.info(f"Successfully undeployed agent {name}")
1280
+ else:
1281
+ logger.error(f"Error undeploying agent {name}")
1282
+
@@ -404,8 +404,11 @@ def list_connections(environment: ConnectionEnvironment | None, verbose: bool =
404
404
  "❌"
405
405
  )
406
406
  continue
407
-
408
- connection_type = get_connection_type(security_scheme=conn.security_scheme, auth_type=conn.auth_type)
407
+
408
+ try:
409
+ connection_type = get_connection_type(security_scheme=conn.security_scheme, auth_type=conn.auth_type)
410
+ except:
411
+ connection_type = conn.auth_type
409
412
 
410
413
  if conn.environment == ConnectionEnvironment.DRAFT:
411
414
  draft_table.add_row(