ibm-watsonx-orchestrate 1.0.0__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 (89) hide show
  1. ibm_watsonx_orchestrate/__init__.py +28 -0
  2. ibm_watsonx_orchestrate/agent_builder/__init__.py +0 -0
  3. ibm_watsonx_orchestrate/agent_builder/agents/__init__.py +5 -0
  4. ibm_watsonx_orchestrate/agent_builder/agents/agent.py +27 -0
  5. ibm_watsonx_orchestrate/agent_builder/agents/assistant_agent.py +28 -0
  6. ibm_watsonx_orchestrate/agent_builder/agents/external_agent.py +28 -0
  7. ibm_watsonx_orchestrate/agent_builder/agents/types.py +204 -0
  8. ibm_watsonx_orchestrate/agent_builder/connections/__init__.py +27 -0
  9. ibm_watsonx_orchestrate/agent_builder/connections/connections.py +123 -0
  10. ibm_watsonx_orchestrate/agent_builder/connections/types.py +260 -0
  11. ibm_watsonx_orchestrate/agent_builder/knowledge_bases/knowledge_base.py +27 -0
  12. ibm_watsonx_orchestrate/agent_builder/knowledge_bases/knowledge_base_requests.py +59 -0
  13. ibm_watsonx_orchestrate/agent_builder/knowledge_bases/types.py +243 -0
  14. ibm_watsonx_orchestrate/agent_builder/tools/__init__.py +4 -0
  15. ibm_watsonx_orchestrate/agent_builder/tools/base_tool.py +36 -0
  16. ibm_watsonx_orchestrate/agent_builder/tools/openapi_tool.py +332 -0
  17. ibm_watsonx_orchestrate/agent_builder/tools/python_tool.py +195 -0
  18. ibm_watsonx_orchestrate/agent_builder/tools/types.py +162 -0
  19. ibm_watsonx_orchestrate/agent_builder/utils/__init__.py +0 -0
  20. ibm_watsonx_orchestrate/agent_builder/utils/pydantic_utils.py +149 -0
  21. ibm_watsonx_orchestrate/cli/__init__.py +0 -0
  22. ibm_watsonx_orchestrate/cli/commands/__init__.py +0 -0
  23. ibm_watsonx_orchestrate/cli/commands/agents/agents_command.py +192 -0
  24. ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +660 -0
  25. ibm_watsonx_orchestrate/cli/commands/channels/channels_command.py +15 -0
  26. ibm_watsonx_orchestrate/cli/commands/channels/channels_controller.py +16 -0
  27. ibm_watsonx_orchestrate/cli/commands/channels/types.py +15 -0
  28. ibm_watsonx_orchestrate/cli/commands/channels/webchat/channels_webchat_command.py +32 -0
  29. ibm_watsonx_orchestrate/cli/commands/channels/webchat/channels_webchat_controller.py +141 -0
  30. ibm_watsonx_orchestrate/cli/commands/chat/chat_command.py +43 -0
  31. ibm_watsonx_orchestrate/cli/commands/connections/connections_command.py +307 -0
  32. ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +517 -0
  33. ibm_watsonx_orchestrate/cli/commands/environment/environment_command.py +78 -0
  34. ibm_watsonx_orchestrate/cli/commands/environment/environment_controller.py +189 -0
  35. ibm_watsonx_orchestrate/cli/commands/environment/types.py +9 -0
  36. ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_command.py +79 -0
  37. ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_controller.py +201 -0
  38. ibm_watsonx_orchestrate/cli/commands/login/login_command.py +17 -0
  39. ibm_watsonx_orchestrate/cli/commands/models/models_command.py +128 -0
  40. ibm_watsonx_orchestrate/cli/commands/server/server_command.py +623 -0
  41. ibm_watsonx_orchestrate/cli/commands/settings/__init__.py +0 -0
  42. ibm_watsonx_orchestrate/cli/commands/settings/observability/__init__.py +0 -0
  43. ibm_watsonx_orchestrate/cli/commands/settings/observability/langfuse/__init__.py +0 -0
  44. ibm_watsonx_orchestrate/cli/commands/settings/observability/langfuse/langfuse_command.py +175 -0
  45. ibm_watsonx_orchestrate/cli/commands/settings/observability/observability_command.py +11 -0
  46. ibm_watsonx_orchestrate/cli/commands/settings/settings_command.py +10 -0
  47. ibm_watsonx_orchestrate/cli/commands/tools/tools_command.py +85 -0
  48. ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +564 -0
  49. ibm_watsonx_orchestrate/cli/commands/tools/types.py +10 -0
  50. ibm_watsonx_orchestrate/cli/config.py +226 -0
  51. ibm_watsonx_orchestrate/cli/main.py +32 -0
  52. ibm_watsonx_orchestrate/client/__init__.py +0 -0
  53. ibm_watsonx_orchestrate/client/agents/agent_client.py +46 -0
  54. ibm_watsonx_orchestrate/client/agents/assistant_agent_client.py +38 -0
  55. ibm_watsonx_orchestrate/client/agents/external_agent_client.py +38 -0
  56. ibm_watsonx_orchestrate/client/analytics/__init__.py +0 -0
  57. ibm_watsonx_orchestrate/client/analytics/llm/__init__.py +0 -0
  58. ibm_watsonx_orchestrate/client/analytics/llm/analytics_llm_client.py +50 -0
  59. ibm_watsonx_orchestrate/client/base_api_client.py +113 -0
  60. ibm_watsonx_orchestrate/client/base_service_instance.py +10 -0
  61. ibm_watsonx_orchestrate/client/client.py +71 -0
  62. ibm_watsonx_orchestrate/client/client_errors.py +359 -0
  63. ibm_watsonx_orchestrate/client/connections/__init__.py +10 -0
  64. ibm_watsonx_orchestrate/client/connections/connections_client.py +162 -0
  65. ibm_watsonx_orchestrate/client/connections/utils.py +27 -0
  66. ibm_watsonx_orchestrate/client/credentials.py +123 -0
  67. ibm_watsonx_orchestrate/client/knowledge_bases/knowledge_base_client.py +46 -0
  68. ibm_watsonx_orchestrate/client/local_service_instance.py +91 -0
  69. ibm_watsonx_orchestrate/client/service_instance.py +73 -0
  70. ibm_watsonx_orchestrate/client/tools/tool_client.py +41 -0
  71. ibm_watsonx_orchestrate/client/utils.py +95 -0
  72. ibm_watsonx_orchestrate/docker/compose-lite.yml +595 -0
  73. ibm_watsonx_orchestrate/docker/default.env +125 -0
  74. ibm_watsonx_orchestrate/docker/sdk/ibm_watsonx_orchestrate-0.6.0-py3-none-any.whl +0 -0
  75. ibm_watsonx_orchestrate/docker/sdk/ibm_watsonx_orchestrate-0.6.0.tar.gz +0 -0
  76. ibm_watsonx_orchestrate/docker/start-up.sh +61 -0
  77. ibm_watsonx_orchestrate/docker/tempus/common-config.yaml +1 -0
  78. ibm_watsonx_orchestrate/run/__init__.py +0 -0
  79. ibm_watsonx_orchestrate/run/connections.py +40 -0
  80. ibm_watsonx_orchestrate/utils/__init__.py +0 -0
  81. ibm_watsonx_orchestrate/utils/logging/__init__.py +0 -0
  82. ibm_watsonx_orchestrate/utils/logging/logger.py +26 -0
  83. ibm_watsonx_orchestrate/utils/logging/logging.yaml +18 -0
  84. ibm_watsonx_orchestrate/utils/utils.py +15 -0
  85. ibm_watsonx_orchestrate-1.0.0.dist-info/METADATA +34 -0
  86. ibm_watsonx_orchestrate-1.0.0.dist-info/RECORD +89 -0
  87. ibm_watsonx_orchestrate-1.0.0.dist-info/WHEEL +4 -0
  88. ibm_watsonx_orchestrate-1.0.0.dist-info/entry_points.txt +2 -0
  89. ibm_watsonx_orchestrate-1.0.0.dist-info/licenses/LICENSE +22 -0
@@ -0,0 +1,660 @@
1
+ import yaml
2
+ import json
3
+ import rich
4
+ import requests
5
+ import importlib
6
+ import inspect
7
+ import sys
8
+ import logging
9
+ from pathlib import Path
10
+ from copy import deepcopy
11
+
12
+ from typing import Iterable, List
13
+ from ibm_watsonx_orchestrate.cli.commands.tools.tools_controller import import_python_tool
14
+
15
+ from ibm_watsonx_orchestrate.agent_builder.agents import (
16
+ Agent,
17
+ ExternalAgent,
18
+ AssistantAgent,
19
+ AgentKind,
20
+ SpecVersion
21
+ )
22
+ from ibm_watsonx_orchestrate.client.agents.agent_client import AgentClient
23
+ from ibm_watsonx_orchestrate.client.agents.external_agent_client import ExternalAgentClient
24
+ from ibm_watsonx_orchestrate.client.agents.assistant_agent_client import AssistantAgentClient
25
+ from ibm_watsonx_orchestrate.client.tools.tool_client import ToolClient
26
+ from ibm_watsonx_orchestrate.client.connections import get_connections_client
27
+ from ibm_watsonx_orchestrate.client.knowledge_bases.knowledge_base_client import KnowledgeBaseClient
28
+
29
+ from ibm_watsonx_orchestrate.client.utils import instantiate_client
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+ def import_python_agent(file: str) -> List[Agent | ExternalAgent | AssistantAgent]:
34
+ # Import tools
35
+ import_python_tool(file)
36
+
37
+ file_path = Path(file)
38
+ file_directory = file_path.parent
39
+ file_name = file_path.stem
40
+ sys.path.append(str(file_directory))
41
+ module = importlib.import_module(file_name)
42
+ del sys.path[-1]
43
+
44
+ agents = []
45
+ for _, obj in inspect.getmembers(module):
46
+ if isinstance(obj, Agent) or isinstance(obj, ExternalAgent) or isinstance(obj, AssistantAgent):
47
+ agents.append(obj)
48
+ return agents
49
+
50
+
51
+ def create_agent_from_spec(file:str, kind:str) -> Agent | ExternalAgent | AssistantAgent:
52
+ if not kind:
53
+ kind = AgentKind.NATIVE
54
+ match kind:
55
+ case AgentKind.NATIVE:
56
+ agent = Agent.from_spec(file)
57
+ case AgentKind.EXTERNAL:
58
+ agent = ExternalAgent.from_spec(file)
59
+ case AgentKind.ASSISTANT:
60
+ agent = AssistantAgent.from_spec(file)
61
+ case _:
62
+ raise ValueError("'kind' must be either 'native' or 'external'")
63
+
64
+ return agent
65
+
66
+ def parse_file(file: str) -> List[Agent | ExternalAgent | AssistantAgent]:
67
+ if file.endswith('.yaml') or file.endswith('.yml') or file.endswith(".json"):
68
+ with open(file, 'r') as f:
69
+ if file.endswith(".json"):
70
+ content = json.load(f)
71
+ else:
72
+ content = yaml.load(f, Loader=yaml.SafeLoader)
73
+ agent = create_agent_from_spec(file=file, kind=content.get("kind"))
74
+ return [agent]
75
+ elif file.endswith('.py'):
76
+ agents = import_python_agent(file)
77
+ return agents
78
+ else:
79
+ raise ValueError("file must end in .json, .yaml, .yml or .py")
80
+
81
+ def parse_create_native_args(name: str, kind: AgentKind, description: str | None, **args) -> dict:
82
+ agent_details = {
83
+ "name": name,
84
+ "kind": kind,
85
+ "description": description,
86
+ "llm": args.get("llm"),
87
+ "style": args.get("style"),
88
+ }
89
+
90
+ collaborators = args.get("collaborators", [])
91
+ collaborators = collaborators if collaborators else []
92
+ collaborators = [x.strip() for x in collaborators if x.strip() != ""]
93
+ agent_details["collaborators"] = collaborators
94
+
95
+ tools = args.get("tools", [])
96
+ tools = tools if tools else []
97
+ tools = [x.strip() for x in tools if x.strip() != ""]
98
+ agent_details["tools"] = tools
99
+
100
+ knowledge_base = args.get("knowledge_base", [])
101
+ knowledge_base = knowledge_base if knowledge_base else []
102
+ knowledge_base = [x.strip() for x in knowledge_base if x.strip() != ""]
103
+ agent_details["knowledge_base"] = knowledge_base
104
+
105
+ return agent_details
106
+
107
+ def parse_create_external_args(name: str, kind: AgentKind, description: str | None, **args) -> dict:
108
+ agent_details = {
109
+ "name": name,
110
+ "kind": kind,
111
+ "description": description,
112
+ "title": args.get("title"),
113
+ "api_url": args.get("api_url"),
114
+ "auth_scheme": args.get("auth_scheme"),
115
+ "auth_config": args.get("auth_config", {}),
116
+ "provider": args.get("provider"),
117
+ "tags": args.get("tags", []),
118
+ "chat_params": args.get("chat_params", {}),
119
+ "config": args.get("config", {}),
120
+ "nickname": args.get("nickname"),
121
+ "app_id": args.get("app_id"),
122
+ }
123
+
124
+ return agent_details
125
+
126
+ def parse_create_assistant_args(name: str, kind: AgentKind, description: str | None, **args) -> dict:
127
+ agent_details = {
128
+ "name": name,
129
+ "kind": kind,
130
+ "description": description,
131
+ "title": args.get("title"),
132
+ "tags": args.get("tags", []),
133
+ "config": args.get("config", {}),
134
+ "nickname": args.get("nickname"),
135
+ }
136
+
137
+ return agent_details
138
+
139
+ def get_conn_id_from_app_id(app_id: str) -> str:
140
+ connections_client = get_connections_client()
141
+ connection = connections_client.get_draft_by_app_id(app_id=app_id)
142
+ if not connection:
143
+ logger.error(f"No connection exits with the app-id '{app_id}'")
144
+ exit(1)
145
+ return connection.connection_id
146
+
147
+ class AgentsController:
148
+ def __init__(self):
149
+ self.native_client = None
150
+ self.external_client = None
151
+ self.assistant_client = None
152
+ self.tool_client = None
153
+ self.knowledge_base_client = None
154
+
155
+ def get_native_client(self):
156
+ if not self.native_client:
157
+ self.native_client = instantiate_client(AgentClient)
158
+ return self.native_client
159
+
160
+ def get_external_client(self):
161
+ if not self.external_client:
162
+ self.external_client = instantiate_client(ExternalAgentClient)
163
+ return self.external_client
164
+
165
+ def get_assistant_client(self):
166
+ if not self.assistant_client:
167
+ self.assistant_client = instantiate_client(AssistantAgentClient)
168
+ return self.assistant_client
169
+
170
+ def get_tool_client(self):
171
+ if not self.tool_client:
172
+ self.tool_client = instantiate_client(ToolClient)
173
+ return self.tool_client
174
+
175
+ def get_knowledge_base_client(self):
176
+ if not self.knowledge_base_client:
177
+ self.knowledge_base_client = instantiate_client(KnowledgeBaseClient)
178
+ return self.knowledge_base_client
179
+
180
+ @staticmethod
181
+ def import_agent(file: str, app_id: str) -> Iterable:
182
+ agents = parse_file(file)
183
+ for agent in agents:
184
+ if app_id and agent.kind != AgentKind.NATIVE and agent.kind != AgentKind.ASSISTANT:
185
+ agent.app_id = app_id
186
+ return agents
187
+
188
+
189
+ @staticmethod
190
+ def generate_agent_spec(
191
+ name: str, kind: AgentKind, description: str, **kwargs
192
+ ) -> Agent | ExternalAgent | AssistantAgent:
193
+ match kind:
194
+ case AgentKind.NATIVE:
195
+ agent_details = parse_create_native_args(name, kind=kind, description=description, **kwargs)
196
+ agent = Agent.model_validate(agent_details)
197
+ AgentsController().persist_record(agent=agent, **kwargs)
198
+ case AgentKind.EXTERNAL:
199
+ agent_details = parse_create_external_args(name, kind=kind, description=description, **kwargs)
200
+ agent = ExternalAgent.model_validate(agent_details)
201
+ AgentsController().persist_record(agent=agent, **kwargs)
202
+ # for agents command without --app-id
203
+ if kwargs.get("app_id") is not None:
204
+ connection_id = get_conn_id_from_app_id(kwargs.get("app_id"))
205
+
206
+ agent.connection_id = connection_id
207
+ case AgentKind.ASSISTANT:
208
+ agent_details = parse_create_assistant_args(name, kind=kind, description=description, **kwargs)
209
+ agent = AssistantAgent.model_validate(agent_details)
210
+ AgentsController().persist_record(agent=agent, **kwargs)
211
+ case _:
212
+ raise ValueError("'kind' must be 'native' or 'external' for agent creation")
213
+ return agent
214
+
215
+ def get_all_agents(self, client: None):
216
+ return {entry["name"]: entry["id"] for entry in client.get()}
217
+
218
+ def dereference_collaborators(self, agent: Agent) -> Agent:
219
+ native_client = self.get_native_client()
220
+ external_client = self.get_external_client()
221
+ assistant_client = self.get_assistant_client()
222
+
223
+ deref_agent = deepcopy(agent)
224
+ matching_native_agents = native_client.get_drafts_by_names(deref_agent.collaborators)
225
+ matching_external_agents = external_client.get_drafts_by_names(deref_agent.collaborators)
226
+ matching_assistant_agents = assistant_client.get_drafts_by_names(deref_agent.collaborators)
227
+ matching_agents = matching_native_agents + matching_external_agents + matching_assistant_agents
228
+ name_id_lookup = {}
229
+ for a in matching_agents:
230
+ if a.get("name") in name_id_lookup:
231
+ logger.error(f"Duplicate draft entries for collaborator '{a.get('name')}'")
232
+ sys.exit(1)
233
+ name_id_lookup[a.get("name")] = a.get("id")
234
+
235
+ deref_collaborators = []
236
+ for name in agent.collaborators:
237
+ id = name_id_lookup.get(name)
238
+ if not id:
239
+ logger.error(f"Failed to find collaborator. No agents found with the name '{name}'")
240
+ sys.exit(1)
241
+ deref_collaborators.append(id)
242
+ deref_agent.collaborators = deref_collaborators
243
+
244
+ return deref_agent
245
+
246
+ def dereference_tools(self, agent: Agent) -> Agent:
247
+ tool_client = self.get_tool_client()
248
+
249
+ deref_agent = deepcopy(agent)
250
+ matching_tools = tool_client.get_drafts_by_names(deref_agent.tools)
251
+
252
+ name_id_lookup = {}
253
+ for tool in matching_tools:
254
+ if tool.get("name") in name_id_lookup:
255
+ logger.error(f"Duplicate draft entries for tol '{tool.get('name')}'")
256
+ sys.exit(1)
257
+ name_id_lookup[tool.get("name")] = tool.get("id")
258
+
259
+ deref_tools = []
260
+ for name in agent.tools:
261
+ id = name_id_lookup.get(name)
262
+ if not id:
263
+ logger.error(f"Failed to find tool. No tools found with the name '{name}'")
264
+ sys.exit(1)
265
+ deref_tools.append(id)
266
+ deref_agent.tools = deref_tools
267
+
268
+ return deref_agent
269
+
270
+ def dereference_knowledge_bases(self, agent: Agent) -> Agent:
271
+ client = self.get_knowledge_base_client()
272
+
273
+ deref_agent = deepcopy(agent)
274
+ matching_knowledge_bases = client.get_by_names(deref_agent.knowledge_base)
275
+
276
+ name_id_lookup = {}
277
+ for kb in matching_knowledge_bases:
278
+ if kb.get("name") in name_id_lookup:
279
+ logger.error(f"Duplicate draft entries for knowledge base '{kb.get('name')}'")
280
+ sys.exit(1)
281
+ name_id_lookup[kb.get("name")] = kb.get("id")
282
+
283
+ deref_knowledge_bases = []
284
+ for name in agent.knowledge_base:
285
+ id = name_id_lookup.get(name)
286
+ if not id:
287
+ logger.error(f"Failed to find knowledge base. No knowledge base found with the name '{name}'")
288
+ sys.exit(1)
289
+ deref_knowledge_bases.append(id)
290
+ deref_agent.knowledge_base = deref_knowledge_bases
291
+
292
+ return deref_agent
293
+
294
+ @staticmethod
295
+ def dereference_app_id(agent: ExternalAgent | AssistantAgent) -> ExternalAgent | AssistantAgent:
296
+ if agent.kind == AgentKind.EXTERNAL:
297
+ agent.connection_id = get_conn_id_from_app_id(agent.app_id)
298
+ else:
299
+ agent.config.connection_id = get_conn_id_from_app_id(agent.config.app_id)
300
+
301
+ return agent
302
+
303
+
304
+ def dereference_native_agent_dependencies(self, agent: Agent) -> Agent:
305
+ if agent.collaborators and len(agent.collaborators):
306
+ agent = self.dereference_collaborators(agent)
307
+ if agent.tools and len(agent.tools):
308
+ agent = self.dereference_tools(agent)
309
+ if agent.knowledge_base and len(agent.knowledge_base):
310
+ agent = self.dereference_knowledge_bases(agent)
311
+
312
+ return agent
313
+
314
+ def dereference_external_or_assistant_agent_dependencies(self, agent: ExternalAgent | AssistantAgent) -> ExternalAgent | AssistantAgent:
315
+ agent_dict = agent.model_dump()
316
+
317
+ if agent_dict.get("app_id") or agent.config.model_dump().get("app_id"):
318
+ agent = self.dereference_app_id(agent)
319
+
320
+ return agent
321
+
322
+ def dereference_agent_dependencies(self, agent: Agent ) -> Agent | ExternalAgent | AssistantAgent:
323
+ if isinstance(agent, Agent):
324
+ return self.dereference_native_agent_dependencies(agent)
325
+ if isinstance(agent, ExternalAgent) or isinstance(agent, AssistantAgent):
326
+ return self.dereference_external_or_assistant_agent_dependencies(agent)
327
+
328
+
329
+ def publish_or_update_agents(
330
+ self, agents: Iterable[Agent]
331
+ ):
332
+ for agent in agents:
333
+ agent_name = agent.name
334
+
335
+ native_client = self.get_native_client()
336
+ external_client = self.get_external_client()
337
+ assistant_client = self.get_assistant_client()
338
+
339
+ existing_native_agents = native_client.get_draft_by_name(agent_name)
340
+ existing_native_agents = [Agent.model_validate(agent) for agent in existing_native_agents]
341
+ existing_external_clients = external_client.get_draft_by_name(agent_name)
342
+ existing_external_clients = [ExternalAgent.model_validate(agent) for agent in existing_external_clients]
343
+ existing_assistant_clients = assistant_client.get_draft_by_name(agent_name)
344
+ existing_assistant_clients = [AssistantAgent.model_validate(agent) for agent in existing_assistant_clients]
345
+
346
+ all_existing_agents = existing_external_clients + existing_native_agents + existing_assistant_clients
347
+ agent = self.dereference_agent_dependencies(agent)
348
+
349
+ agent_kind = agent.kind
350
+
351
+ if len(all_existing_agents) > 1:
352
+ logger.error(f"Multiple agents with the name '{agent_name}' found. Failed to update agent")
353
+ sys.exit(1)
354
+
355
+ if len(all_existing_agents) > 0:
356
+ existing_agent = all_existing_agents[0]
357
+
358
+ if agent_name == existing_agent.name:
359
+ if agent_kind != existing_agent.kind:
360
+ logger.error(f"An agent with the name '{agent_name}' already exists with a different kind. Failed to create agent")
361
+ sys.exit(1)
362
+ agent_id = existing_agent.id
363
+ self.update_agent(agent_id=agent_id, agent=agent)
364
+ else:
365
+ self.publish_agent(agent)
366
+
367
+ def publish_agent(self, agent: Agent, **kwargs) -> None:
368
+ if isinstance(agent, Agent):
369
+ self.get_native_client().create(agent.model_dump())
370
+ logger.info(f"Agent '{agent.name}' imported successfully")
371
+ if isinstance(agent, ExternalAgent):
372
+ self.get_external_client().create(agent.model_dump())
373
+ logger.info(f"External Agent '{agent.name}' imported successfully")
374
+ if isinstance(agent, AssistantAgent):
375
+ self.get_assistant_client().create(agent.model_dump(by_alias=True))
376
+ logger.info(f"Assistant Agent '{agent.name}' imported successfully")
377
+
378
+ def update_agent(
379
+ self, agent_id: str, agent: Agent, **kwargs
380
+ ) -> None:
381
+ if isinstance(agent, Agent):
382
+ logger.info(f"Existing Agent '{agent.name}' found. Updating...")
383
+ self.get_native_client().update(agent_id, agent.model_dump())
384
+ logger.info(f"Agent '{agent.name}' updated successfully")
385
+ if isinstance(agent, ExternalAgent):
386
+ logger.info(f"Existing External Agent '{agent.name}' found. Updating...")
387
+ self.get_external_client().update(agent_id, agent.model_dump())
388
+ logger.info(f"External Agent '{agent.name}' updated successfully")
389
+ if isinstance(agent, AssistantAgent):
390
+ logger.info(f"Existing Assistant Agent '{agent.name}' found. Updating...")
391
+ self.get_assistant_client().update(agent_id, agent.model_dump(by_alias=True))
392
+ logger.info(f"Assistant Agent '{agent.name}' updated successfully")
393
+
394
+ @staticmethod
395
+ def persist_record(agent: Agent, **kwargs):
396
+ if "output_file" in kwargs and kwargs["output_file"] is not None:
397
+ agent.spec_version = SpecVersion.V1
398
+ agent.dump_spec(kwargs["output_file"])
399
+
400
+ def get_agent_tool_names(self, tool_ids: List[str]) -> List[str]:
401
+ """Retrieve tool names for a given agent based on tool IDs."""
402
+ tool_client = self.get_tool_client()
403
+ tools = []
404
+ for tool_id in tool_ids:
405
+ try:
406
+ tool = tool_client.get_draft_by_id(tool_id)
407
+ tools.append(tool["name"])
408
+ except Exception as e:
409
+ logger.warning(f"Tool with ID {tool_id} not found. Returning Tool ID")
410
+ tools.append(tool_id)
411
+ return tools
412
+
413
+ def get_agent_collaborator_names(self, agent_ids: List[str]) -> List[str]:
414
+ """Retrieve collaborator names for a given agent based on collaborator IDs."""
415
+ collaborator_client = self.get_native_client()
416
+ external_client = self.get_external_client()
417
+ assistant_client = self.get_assistant_client()
418
+ collaborators = []
419
+
420
+ for agent_id in agent_ids:
421
+ try:
422
+ # First try resolving from native agents
423
+ collaborator = collaborator_client.get_draft_by_id(agent_id)
424
+ if collaborator:
425
+ collaborators.append(collaborator["name"])
426
+ continue
427
+ except Exception:
428
+ pass
429
+
430
+ try:
431
+ # If not found in native, check external agents
432
+ external_collaborator = external_client.get_draft_by_id(agent_id)
433
+ if external_collaborator:
434
+ collaborators.append(external_collaborator["name"])
435
+ continue
436
+ except Exception:
437
+ pass
438
+
439
+ try:
440
+ # If not found in native or external, check assistant agents
441
+ assistant_collaborator = assistant_client.get_draft_by_id(agent_id)
442
+ if assistant_collaborator:
443
+ collaborators.append(assistant_collaborator["name"])
444
+ continue
445
+ except Exception:
446
+ pass
447
+
448
+ logger.warning(f"Collaborator with ID {agent_id} not found. Returning Collaborator ID")
449
+ collaborators.append(agent_id)
450
+
451
+ return collaborators
452
+
453
+ def get_agent_knowledge_base_names(self, knowlede_base_ids: List[str]) -> List[str]:
454
+ """Retrieve knowledge base names for a given agent based on knowledge base IDs."""
455
+ client = self.get_knowledge_base_client()
456
+ knowledge_bases = []
457
+ for id in knowlede_base_ids:
458
+ try:
459
+ kb = client.get_by_id(id)
460
+ knowledge_bases.append(kb["name"])
461
+ except Exception as e:
462
+ logger.warning(f"Knowledge base with ID {id} not found. Returning Tool ID")
463
+ knowledge_bases.append(id)
464
+ return knowledge_bases
465
+
466
+ def list_agents(self, kind: AgentKind=None, verbose: bool=False):
467
+ if kind == AgentKind.NATIVE or kind is None:
468
+ response = self.get_native_client().get()
469
+ native_agents = [Agent.model_validate(agent) for agent in response]
470
+
471
+ if verbose:
472
+ agents_list = []
473
+ for agent in native_agents:
474
+
475
+ agents_list.append(json.loads(agent.dumps_spec()))
476
+
477
+ rich.print(rich.json.JSON(json.dumps(agents_list, indent=4)))
478
+ else:
479
+ native_table = rich.table.Table(
480
+ show_header=True,
481
+ header_style="bold white",
482
+ title="Agents",
483
+ show_lines=True
484
+ )
485
+ column_args = {
486
+ "Name": {},
487
+ "Description": {},
488
+ "LLM": {"overflow": "fold"},
489
+ "Style": {},
490
+ "Collaborators": {},
491
+ "Tools": {},
492
+ "Knowledge Base": {},
493
+ "ID": {},
494
+ }
495
+ for column in column_args:
496
+ native_table.add_column(column, **column_args[column])
497
+
498
+ for agent in native_agents:
499
+ tool_names = self.get_agent_tool_names(agent.tools)
500
+ knowledge_base_names = self.get_agent_knowledge_base_names(agent.knowledge_base)
501
+ collaborator_names = self.get_agent_collaborator_names(agent.collaborators)
502
+
503
+ native_table.add_row(
504
+ agent.name,
505
+ agent.description,
506
+ agent.llm,
507
+ agent.style,
508
+ ", ".join(collaborator_names),
509
+ ", ".join(tool_names),
510
+ ", ".join(knowledge_base_names),
511
+ agent.id,
512
+ )
513
+ rich.print(native_table)
514
+
515
+
516
+ if kind == AgentKind.EXTERNAL or kind is None:
517
+ response = self.get_external_client().get()
518
+
519
+ external_agents = [ExternalAgent.model_validate(agent) for agent in response]
520
+
521
+ response_dict = {agent["id"]: agent for agent in response}
522
+
523
+ # Insert config values into config as config object is not retruned from api
524
+ for external_agent in external_agents:
525
+ if external_agent.id in response_dict:
526
+ response_data = response_dict[external_agent.id]
527
+ external_agent.config.enable_cot = response_data.get("enable_cot", external_agent.config.enable_cot)
528
+ external_agent.config.hidden = response_data.get("hidden", external_agent.config.hidden)
529
+
530
+ external_agents_list = []
531
+ if verbose:
532
+ for agent in external_agents:
533
+ external_agents_list.append(json.loads(agent.dumps_spec()))
534
+ rich.print(rich.json.JSON(json.dumps(external_agents_list, indent=4)))
535
+ else:
536
+ external_table = rich.table.Table(
537
+ show_header=True,
538
+ header_style="bold white",
539
+ title="External Agents",
540
+ show_lines=True
541
+ )
542
+ column_args = {
543
+ "Name": {},
544
+ "Title": {},
545
+ "Description": {},
546
+ "Tags": {},
547
+ "API URL": {"overflow": "fold"},
548
+ "Chat Params": {},
549
+ "Config": {},
550
+ "Nickname": {},
551
+ "App ID": {},
552
+ "ID": {}
553
+ }
554
+
555
+ for column in column_args:
556
+ external_table.add_column(column, **column_args[column])
557
+
558
+ for agent in external_agents:
559
+ connections_client = get_connections_client()
560
+ app_id = connections_client.get_draft_by_id(agent.connection_id)
561
+
562
+ external_table.add_row(
563
+ agent.name,
564
+ agent.title,
565
+ agent.description,
566
+ ", ".join(agent.tags or []),
567
+ agent.api_url,
568
+ json.dumps(agent.chat_params),
569
+ str(agent.config),
570
+ agent.nickname,
571
+ app_id,
572
+ agent.id
573
+ )
574
+ rich.print(external_table)
575
+
576
+ if kind == AgentKind.ASSISTANT or kind is None:
577
+ response = self.get_assistant_client().get()
578
+
579
+ assistant_agents = [AssistantAgent.model_validate(agent) for agent in response]
580
+
581
+ response_dict = {agent["id"]: agent for agent in response}
582
+
583
+ # Insert config values into config as config object is not retruned from api
584
+ for assistant_agent in assistant_agents:
585
+ if assistant_agent.id in response_dict:
586
+ response_data = response_dict[assistant_agent.id]
587
+ assistant_agent.config.api_version = response_data.get("api_version", assistant_agent.config.api_version)
588
+ assistant_agent.config.assistant_id = response_data.get("assistant_id", assistant_agent.config.assistant_id)
589
+ assistant_agent.config.crn = response_data.get("crn", assistant_agent.config.crn)
590
+ assistant_agent.config.service_instance_url = response_data.get("service_instance_url", assistant_agent.config.service_instance_url)
591
+ assistant_agent.config.environment_id = response_data.get("environment_id", assistant_agent.config.environment_id)
592
+ assistant_agent.config.authorization_url = response_data.get("authorization_url", assistant_agent.config.authorization_url)
593
+
594
+ if verbose:
595
+ for agent in assistant_agents:
596
+ rich.print(agent.dumps_spec())
597
+ else:
598
+ assistants_table = rich.table.Table(
599
+ show_header=True,
600
+ header_style="bold white",
601
+ title="Assistant Agents",
602
+ show_lines=True)
603
+ column_args = {
604
+ "Name": {},
605
+ "Title": {},
606
+ "Description": {},
607
+ "Tags": {},
608
+ "Nickname": {},
609
+ "CRN": {},
610
+ "Instance URL": {},
611
+ "Assistant ID": {},
612
+ "Environment ID": {},
613
+ "ID": {}
614
+ }
615
+
616
+ for column in column_args:
617
+ assistants_table.add_column(column, **column_args[column])
618
+
619
+ for agent in assistant_agents:
620
+ assistants_table.add_row(
621
+ agent.name,
622
+ agent.title,
623
+ agent.description,
624
+ ", ".join(agent.tags or []),
625
+ agent.nickname,
626
+ agent.config.crn,
627
+ agent.config.service_instance_url,
628
+ agent.config.assistant_id,
629
+ agent.config.environment_id,
630
+ agent.id
631
+ )
632
+ rich.print(assistants_table)
633
+
634
+ def remove_agent(self, name: str, kind: AgentKind):
635
+ try:
636
+ if kind == AgentKind.NATIVE:
637
+ client = self.get_native_client()
638
+ elif kind == AgentKind.EXTERNAL:
639
+ client = self.get_external_client()
640
+ elif kind == AgentKind.ASSISTANT:
641
+ client = self.get_assistant_client()
642
+ else:
643
+ raise ValueError("'kind' must be 'native'")
644
+
645
+ draft_agents = client.get_draft_by_name(name)
646
+ if len(draft_agents) > 1:
647
+ logger.error(f"Multiple '{kind}' agents found with name '{name}'. Failed to delete agent")
648
+ sys.exit(1)
649
+ if len(draft_agents) > 0:
650
+ draft_agent = draft_agents[0]
651
+ agent_id = draft_agent.get("id")
652
+ client.delete(agent_id=agent_id)
653
+
654
+ logger.info(f"Successfully removed agent {name}")
655
+ else:
656
+ logger.warning(f"No agent named '{name}' found")
657
+ except requests.HTTPError as e:
658
+ logger.error(e.response.text)
659
+ exit(1)
660
+
@@ -0,0 +1,15 @@
1
+ import typer
2
+ from ibm_watsonx_orchestrate.cli.commands.channels import channels_controller
3
+ from ibm_watsonx_orchestrate.cli.commands.channels.webchat.channels_webchat_command import channel_webchat
4
+
5
+ channel_app = typer.Typer(no_args_is_help=True)
6
+
7
+ channel_app.add_typer(
8
+ channel_webchat,
9
+ name="webchat",
10
+ help="Integrate with the Webchat Channel, for example exporting an embeddable code snippet can be achieved with the command 'orchestrate channel webchat embed --agent-name=some_agent --env=live'."
11
+ )
12
+
13
+ @channel_app.command(name="list", help="Lists the current supported Channels. A Channel refers to the different platforms you can embed your assistant into, such as web chat: orchestrate channel webchat embed --agent-name=some_agent --env=live")
14
+ def list_channel():
15
+ channels_controller.list_channels()
@@ -0,0 +1,16 @@
1
+ from ibm_watsonx_orchestrate.cli.commands.channels.types import ChannelType
2
+ import rich
3
+ import rich.table
4
+
5
+ def list_channels():
6
+ table = rich.table.Table(show_header=True, header_style="bold white", show_lines=True)
7
+ columns = ["Channel"]
8
+ for col in columns:
9
+ table.add_column(col)
10
+
11
+ for channel in ChannelType.__members__.values():
12
+
13
+ table.add_row(channel)
14
+
15
+ console = rich.console.Console()
16
+ console.print(table)