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.
- ibm_watsonx_orchestrate/__init__.py +2 -1
- ibm_watsonx_orchestrate/agent_builder/agents/types.py +2 -0
- ibm_watsonx_orchestrate/agent_builder/knowledge_bases/types.py +2 -2
- ibm_watsonx_orchestrate/agent_builder/models/types.py +5 -0
- ibm_watsonx_orchestrate/agent_builder/tools/python_tool.py +19 -7
- ibm_watsonx_orchestrate/agent_builder/tools/types.py +5 -3
- ibm_watsonx_orchestrate/agent_builder/voice_configurations/__init__.py +1 -0
- ibm_watsonx_orchestrate/agent_builder/voice_configurations/types.py +98 -0
- ibm_watsonx_orchestrate/cli/commands/agents/agents_command.py +20 -0
- ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +170 -1
- ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +5 -2
- ibm_watsonx_orchestrate/cli/commands/copilot/copilot_controller.py +103 -20
- ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_controller.py +19 -12
- ibm_watsonx_orchestrate/cli/commands/models/model_provider_mapper.py +17 -13
- ibm_watsonx_orchestrate/cli/commands/server/server_command.py +17 -4
- ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +6 -1
- ibm_watsonx_orchestrate/cli/commands/voice_configurations/voice_configurations_command.py +58 -0
- ibm_watsonx_orchestrate/cli/commands/voice_configurations/voice_configurations_controller.py +173 -0
- ibm_watsonx_orchestrate/cli/main.py +2 -0
- ibm_watsonx_orchestrate/client/agents/agent_client.py +64 -1
- ibm_watsonx_orchestrate/client/connections/connections_client.py +14 -2
- ibm_watsonx_orchestrate/client/copilot/cpe/copilot_cpe_client.py +5 -3
- ibm_watsonx_orchestrate/client/voice_configurations/voice_configurations_client.py +75 -0
- ibm_watsonx_orchestrate/docker/compose-lite.yml +23 -2
- ibm_watsonx_orchestrate/docker/default.env +16 -12
- ibm_watsonx_orchestrate/flow_builder/flows/__init__.py +2 -2
- ibm_watsonx_orchestrate/flow_builder/flows/flow.py +29 -24
- ibm_watsonx_orchestrate/flow_builder/types.py +109 -17
- ibm_watsonx_orchestrate/flow_builder/utils.py +7 -3
- {ibm_watsonx_orchestrate-1.9.0b1.dist-info → ibm_watsonx_orchestrate-1.10.0b0.dist-info}/METADATA +1 -1
- {ibm_watsonx_orchestrate-1.9.0b1.dist-info → ibm_watsonx_orchestrate-1.10.0b0.dist-info}/RECORD +34 -29
- {ibm_watsonx_orchestrate-1.9.0b1.dist-info → ibm_watsonx_orchestrate-1.10.0b0.dist-info}/WHEEL +0 -0
- {ibm_watsonx_orchestrate-1.9.0b1.dist-info → ibm_watsonx_orchestrate-1.10.0b0.dist-info}/entry_points.txt +0 -0
- {ibm_watsonx_orchestrate-1.9.0b1.dist-info → ibm_watsonx_orchestrate-1.10.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -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
|
-
|
195
|
-
|
196
|
-
if
|
197
|
-
|
198
|
-
|
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]] =
|
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
|
-
|
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(
|