ibm-watsonx-orchestrate 1.11.0b0__py3-none-any.whl → 1.11.0b1__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 (23) hide show
  1. ibm_watsonx_orchestrate/__init__.py +2 -1
  2. ibm_watsonx_orchestrate/agent_builder/agents/types.py +13 -0
  3. ibm_watsonx_orchestrate/agent_builder/connections/connections.py +5 -2
  4. ibm_watsonx_orchestrate/agent_builder/knowledge_bases/types.py +24 -9
  5. ibm_watsonx_orchestrate/cli/commands/agents/agents_command.py +10 -2
  6. ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +404 -173
  7. ibm_watsonx_orchestrate/cli/commands/copilot/copilot_controller.py +6 -2
  8. ibm_watsonx_orchestrate/cli/commands/environment/environment_command.py +1 -1
  9. ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_command.py +174 -2
  10. ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_controller.py +93 -9
  11. ibm_watsonx_orchestrate/client/base_api_client.py +31 -10
  12. ibm_watsonx_orchestrate/client/connections/connections_client.py +14 -0
  13. ibm_watsonx_orchestrate/client/service_instance.py +19 -34
  14. ibm_watsonx_orchestrate/client/utils.py +3 -1
  15. ibm_watsonx_orchestrate/docker/compose-lite.yml +2 -1
  16. ibm_watsonx_orchestrate/docker/default.env +10 -10
  17. ibm_watsonx_orchestrate/flow_builder/flows/flow.py +3 -1
  18. ibm_watsonx_orchestrate/flow_builder/types.py +252 -1
  19. {ibm_watsonx_orchestrate-1.11.0b0.dist-info → ibm_watsonx_orchestrate-1.11.0b1.dist-info}/METADATA +2 -2
  20. {ibm_watsonx_orchestrate-1.11.0b0.dist-info → ibm_watsonx_orchestrate-1.11.0b1.dist-info}/RECORD +23 -23
  21. {ibm_watsonx_orchestrate-1.11.0b0.dist-info → ibm_watsonx_orchestrate-1.11.0b1.dist-info}/WHEEL +0 -0
  22. {ibm_watsonx_orchestrate-1.11.0b0.dist-info → ibm_watsonx_orchestrate-1.11.0b1.dist-info}/entry_points.txt +0 -0
  23. {ibm_watsonx_orchestrate-1.11.0b0.dist-info → ibm_watsonx_orchestrate-1.11.0b1.dist-info}/licenses/LICENSE +0 -0
@@ -12,6 +12,7 @@ from pathlib import Path
12
12
  from copy import deepcopy
13
13
 
14
14
  from typing import Iterable, List, TypeVar
15
+ from pydantic import BaseModel
15
16
  from ibm_watsonx_orchestrate.agent_builder.agents.types import AgentStyle
16
17
  from ibm_watsonx_orchestrate.agent_builder.tools.types import ToolSpec
17
18
  from ibm_watsonx_orchestrate.cli.commands.tools.tools_controller import import_python_tool, ToolsController
@@ -40,11 +41,24 @@ from ibm_watsonx_orchestrate.utils.utils import check_file_in_zip
40
41
  from rich.console import Console
41
42
  from rich.progress import Progress, SpinnerColumn, TextColumn
42
43
 
44
+ from enum import Enum
45
+
43
46
  logger = logging.getLogger(__name__)
44
47
 
45
48
  # Helper generic type for any agent
46
49
  AnyAgentT = TypeVar("AnyAgentT", bound=Agent | ExternalAgent | AssistantAgent)
47
50
 
51
+ class AgentListFormats(str, Enum):
52
+ Table = "table"
53
+ JSON = "json"
54
+
55
+ def __str__(self):
56
+ return self.value
57
+
58
+ def __repr__(self):
59
+ return repr(self.value)
60
+
61
+
48
62
  def import_python_agent(file: str) -> List[Agent | ExternalAgent | AssistantAgent]:
49
63
  # Import tools
50
64
  import_python_tool(file)
@@ -100,6 +114,7 @@ def parse_create_native_args(name: str, kind: AgentKind, description: str | None
100
114
  "name": name,
101
115
  "kind": kind,
102
116
  "description": description,
117
+ "instructions": args.get("instructions"),
103
118
  "llm": args.get("llm"),
104
119
  "style": args.get("style"),
105
120
  "custom_join_tool": args.get("custom_join_tool"),
@@ -804,213 +819,429 @@ class AgentsController:
804
819
  logger.warning(f"Knowledge base with ID {id} not found. Returning Tool ID")
805
820
  knowledge_bases.append(id)
806
821
  return knowledge_bases
807
-
808
- def list_agents(self, kind: AgentKind=None, verbose: bool=False):
822
+
823
+ def _fetch_and_parse_agents(self, target_agent_kind: AgentKind) -> tuple[List[Agent] | List[ExternalAgent] | List[AssistantAgent], List[List[str]]]:
809
824
  parse_errors = []
825
+ target_kind_display_name = None
826
+ target_kind_class = None
827
+ agent_client = None
810
828
 
811
- if verbose:
812
- verbose_output_dictionary = {
813
- "native":[],
814
- "assistant":[],
815
- "external":[]
816
- }
829
+ match(target_agent_kind):
830
+ case AgentKind.NATIVE:
831
+ target_kind_display_name = "Agent"
832
+ target_kind_class = Agent
833
+ agent_client = self.get_native_client()
834
+ case AgentKind.EXTERNAL:
835
+ target_kind_display_name = "External Agent"
836
+ target_kind_class = ExternalAgent
837
+ agent_client = self.get_external_client()
838
+ case AgentKind.ASSISTANT:
839
+ target_kind_display_name = "Assistant Agent"
840
+ target_kind_class = AssistantAgent
841
+ agent_client = self.get_assistant_client()
842
+ case _:
843
+ return ([], [[f"Invalid Agent kind '{target_agent_kind}'"]])
844
+
845
+ response = agent_client.get()
846
+ agents = []
847
+ for agent in response:
848
+ try:
849
+ agents.append(target_kind_class.model_validate(agent))
850
+ except Exception as e:
851
+ name = agent.get('name', None)
852
+ parse_errors.append([
853
+ f"{target_kind_display_name} '{name}' could not be parsed",
854
+ json.dumps(agent),
855
+ e
856
+ ])
857
+ return (agents, parse_errors)
858
+
859
+ def _get_all_unique_agent_resources(self, agents: List[Agent], target_attr: str) -> List[str]:
860
+ """
861
+ Given a list if agents get all the unique values of a certain field
862
+ Example: agent1.tools = [1 ,2 ,3] and agent2.tools = [2, 4, 5] then return [1, 2, 3, 4, 5]
863
+ Example: agent1.id = "123" and agent2.id = "456" then return ["123", "456"]
864
+
865
+ Args:
866
+ agents: List of agents
867
+ target_attr: The name of the field to access and get unique elements
868
+
869
+ Returns:
870
+ A list of unique elements from across all agents
871
+ """
872
+ all_ids = set()
873
+ for agent in agents:
874
+ attr_value = getattr(agent, target_attr, None)
875
+ if attr_value:
876
+ if isinstance(attr_value, list):
877
+ all_ids.update(attr_value)
878
+ else:
879
+ all_ids.add(attr_value)
880
+ return list(all_ids)
881
+
882
+ def _construct_lut_agent_resource(self, resource_list: List[dict], key_attr: str, value_attr) -> dict:
883
+ """
884
+ Given a list of dictionaries build a key -> value look up table
885
+ Example [{id: 1, name: obj1}, {id: 2, name: obj2}] return {1: obj1, 2: obj2}
886
+
887
+ Args:
888
+ resource_list: A list of dictionries from which to build the lookup table from
889
+ key_attr: The name of the field whose value will form the key of the lookup table
890
+ value_attrL The name of the field whose value will form the value of the lookup table
891
+
892
+ Returns:
893
+ A lookup table
894
+ """
895
+ lut = {}
896
+ for resource in resource_list:
897
+ if isinstance(resource, BaseModel):
898
+ resource = resource.model_dump()
899
+ lut[resource.get(key_attr, None)] = resource.get(value_attr, None)
900
+ return lut
901
+
902
+ def _lookup_agent_resource_value(
903
+ self,
904
+ agent: Agent,
905
+ lookup_table: dict[str, str],
906
+ target_attr: str,
907
+ target_attr_display_name: str
908
+ ) -> List[str] | str | None:
909
+ """
910
+ Using a lookup table convert all the strings in a given field of an agent into their equivalent in the lookup table
911
+ Example: lookup_table={1: obj1, 2: obj2} agent=Agent(tools=[1,2]) return. [obj1, obj2]
912
+
913
+ Args:
914
+ agent: An agent
915
+ lookup_table: A dictionary that maps one value to another
916
+ target_attr: The field to convert on the provided agent
917
+ target_attr_display_name: The name of the field to be displayed in the event of an error
918
+ """
919
+ attr_value = getattr(agent, target_attr, None)
920
+ if not attr_value:
921
+ return
922
+
923
+ if isinstance(attr_value, list):
924
+ new_resource_list=[]
925
+ for value in attr_value:
926
+ if value in lookup_table:
927
+ new_resource_list.append(lookup_table[value])
928
+ else:
929
+ logger.warning(f"{target_attr_display_name} with ID '{value}' not found. Returning {target_attr_display_name} ID")
930
+ new_resource_list.append(value)
931
+ return new_resource_list
932
+ else:
933
+ if attr_value in lookup_table:
934
+ return lookup_table[attr_value]
935
+ else:
936
+ logger.warning(f"{target_attr_display_name} with ID '{attr_value}' not found. Returning {target_attr_display_name} ID")
937
+ return attr_value
938
+
939
+ def _batch_request_resource(self, client_fn, ids, batch_size=50) -> List[dict]:
940
+ resources = []
941
+ for i in range(0, len(ids), batch_size):
942
+ chunk = ids[i:i + batch_size]
943
+ resources += (client_fn(chunk))
944
+ return resources
945
+
946
+
947
+ def _bulk_resolve_agent_tools(self, agents: List[Agent]) -> List[Agent]:
948
+ new_agents = agents.copy()
949
+ all_tools_ids = self._get_all_unique_agent_resources(new_agents, "tools")
950
+ if not all_tools_ids:
951
+ return new_agents
952
+
953
+ all_tools = self._batch_request_resource(self.get_tool_client().get_drafts_by_ids, all_tools_ids)
954
+
955
+ tool_lut = self._construct_lut_agent_resource(all_tools, "id", "name")
956
+
957
+ for agent in new_agents:
958
+ tool_names = self._lookup_agent_resource_value(agent, tool_lut, "tools", "Tool")
959
+ if tool_names:
960
+ agent.tools = tool_names
961
+ return new_agents
962
+
963
+ # TODO: Once bulk knowledge base is added create a generaic fucntion as opposed to 3 seperate ones
964
+ def _bulk_resolve_agent_knowledge_bases(self, agents: List[Agent]) -> List[Agent]:
965
+ new_agents = agents.copy()
966
+ all_kb_ids = self._get_all_unique_agent_resources(new_agents, "knowledge_base")
967
+
968
+ all_kbs = []
969
+ for id in all_kb_ids:
970
+ try:
971
+ all_kbs.append(self.get_knowledge_base_client().get_by_id(id))
972
+ except:
973
+ continue
974
+
975
+ kb_lut = self._construct_lut_agent_resource(all_kbs, "id", "name")
976
+
977
+ for agent in new_agents:
978
+ kb_names = self._lookup_agent_resource_value(agent, kb_lut, "knowledge_base", "Knowledge Base")
979
+ if kb_names:
980
+ agent.knowledge_base = kb_names
981
+ return new_agents
982
+
983
+ def _bulk_resolve_agent_collaborators(self, agents: List[Agent]) -> List[Agent]:
984
+ new_agents = agents.copy()
985
+ all_collab_ids = self._get_all_unique_agent_resources(new_agents, "collaborators")
986
+ if not all_collab_ids:
987
+ return new_agents
988
+
989
+ native_agents = self._batch_request_resource(self.get_native_client().get_drafts_by_ids, all_collab_ids)
990
+ external_agents = self._batch_request_resource(self.get_external_client().get_drafts_by_ids, all_collab_ids)
991
+ assitant_agents = self._batch_request_resource(self.get_assistant_client().get_drafts_by_ids, all_collab_ids)
992
+
993
+ all_collabs = native_agents + external_agents + assitant_agents
994
+
995
+ collab_lut = self._construct_lut_agent_resource(all_collabs, "id", "name")
996
+
997
+ for agent in new_agents:
998
+ collab_names = self._lookup_agent_resource_value(agent, collab_lut, "collaborators", "Collaborator")
999
+ if collab_names:
1000
+ agent.collaborators = collab_names
1001
+ return new_agents
1002
+
1003
+ def _bulk_resolve_agent_app_ids(self , agents: List[ExternalAgent]) -> List[ExternalAgent]:
1004
+ new_agents = agents.copy()
1005
+ all_conn_ids = self._get_all_unique_agent_resources(new_agents, "connection_id")
1006
+ if not all_conn_ids:
1007
+ return new_agents
1008
+
1009
+ all_connections = self._batch_request_resource(get_connections_client().get_drafts_by_ids, all_conn_ids)
1010
+
1011
+ connection_lut = self._construct_lut_agent_resource(all_connections, "connection_id", "app_id")
1012
+
1013
+ for agent in new_agents:
1014
+ app_id = self._lookup_agent_resource_value(agent, connection_lut, "connection_id", "Connection")
1015
+ if app_id:
1016
+ agent.app_id = app_id
1017
+ return new_agents
1018
+
1019
+ # TODO: Make a shared util
1020
+ def _rich_table_to_markdown(self, table: rich.table.Table) -> str:
1021
+ headers = [column.header for column in table.columns]
1022
+ cols = [[cell for cell in col.cells] for col in table.columns]
1023
+ rows = list(map(list, zip(*cols)))
1024
+
1025
+ # Header row
1026
+ md = "| " + " | ".join(headers) + " |\n"
1027
+ # Separator row
1028
+ md += "| " + " | ".join(["---"] * len(headers)) + " |\n"
1029
+ # # Data rows
1030
+ for row in rows:
1031
+ md += "| " + " | ".join(row) + " |\n"
1032
+ return md
1033
+
1034
+
1035
+
1036
+ def list_agents(self, kind: AgentKind=None, verbose: bool=False, format: AgentListFormats | None = None) -> dict[str, dict] | None:
1037
+ """
1038
+ List agents in the active wxo environment
1039
+
1040
+ Args:
1041
+ kind: Filter to only list a certain kind of agent. Allowed values "native", "assistant", "external"
1042
+ verbose: Show raw json output without table formatting or id to name resolution
1043
+ format: Optional value. If provided print nothing and return a string containing the agents in the requested format. Allowed values "table", "json"
1044
+ """
1045
+ if verbose and format:
1046
+ logger.error("For agents list, `--verbose` and `--format` are mutually exclusive options")
1047
+ sys.exit(1)
1048
+
1049
+ parse_errors = []
1050
+ output_dictionary = {
1051
+ "native": None,
1052
+ "assistant": None,
1053
+ "external": None
1054
+ }
817
1055
 
818
1056
  if kind == AgentKind.NATIVE or kind is None:
819
- response = self.get_native_client().get()
820
- native_agents = []
821
- for agent in response:
822
- try:
823
- native_agents.append(Agent.model_validate(agent))
824
- except Exception as e:
825
- name = agent.get('name', None)
826
- parse_errors.append([
827
- f"Agent '{name}' could not be parsed",
828
- json.dumps(agent),
829
- e
830
- ])
1057
+ native_agents, new_parse_errors = self._fetch_and_parse_agents(AgentKind.NATIVE)
1058
+ parse_errors += new_parse_errors
831
1059
 
832
1060
  if verbose:
833
1061
  agents_list = []
834
1062
  for agent in native_agents:
835
1063
  agents_list.append(json.loads(agent.dumps_spec()))
836
1064
 
837
- verbose_output_dictionary["native"] = agents_list
1065
+ output_dictionary["native"] = agents_list
838
1066
  else:
839
- native_table = rich.table.Table(
840
- show_header=True,
841
- header_style="bold white",
842
- title="Agents",
843
- show_lines=True
844
- )
845
- column_args = {
846
- "Name": {"overflow": "fold"},
847
- "Description": {},
848
- "LLM": {"overflow": "fold"},
849
- "Style": {},
850
- "Collaborators": {},
851
- "Tools": {},
852
- "Knowledge Base": {},
853
- "ID": {"overflow": "fold"},
854
- }
855
- for column in column_args:
856
- native_table.add_column(column, **column_args[column])
857
-
858
- for agent in native_agents:
859
- tool_names = self.get_agent_tool_names(agent.tools)
860
- knowledge_base_names = self.get_agent_knowledge_base_names(agent.knowledge_base)
861
- collaborator_names = self.get_agent_collaborator_names(agent.collaborators)
862
-
863
- native_table.add_row(
864
- agent.name,
865
- agent.description,
866
- agent.llm,
867
- agent.style,
868
- ", ".join(collaborator_names),
869
- ", ".join(tool_names),
870
- ", ".join(knowledge_base_names),
871
- agent.id,
1067
+ resolved_native_agents = self._bulk_resolve_agent_tools(native_agents)
1068
+ resolved_native_agents = self._bulk_resolve_agent_knowledge_bases(resolved_native_agents)
1069
+ resolved_native_agents = self._bulk_resolve_agent_collaborators(resolved_native_agents)
1070
+
1071
+ if format and format == AgentListFormats.JSON:
1072
+ agents_list = []
1073
+ for agent in resolved_native_agents:
1074
+ agents_list.append(json.loads(agent.dumps_spec()))
1075
+
1076
+ output_dictionary["native"] = agents_list
1077
+ else:
1078
+ native_table = rich.table.Table(
1079
+ show_header=True,
1080
+ header_style="bold white",
1081
+ title="Agents",
1082
+ show_lines=True
872
1083
  )
873
- rich.print(native_table)
874
1084
 
1085
+ column_args = {
1086
+ "Name": {"overflow": "fold"},
1087
+ "Description": {},
1088
+ "LLM": {"overflow": "fold"},
1089
+ "Style": {},
1090
+ "Collaborators": {},
1091
+ "Tools": {},
1092
+ "Knowledge Base": {},
1093
+ "ID": {"overflow": "fold"},
1094
+ }
1095
+ for column in column_args:
1096
+ native_table.add_column(column, **column_args[column])
1097
+
1098
+ for agent in resolved_native_agents:
1099
+ native_table.add_row(
1100
+ agent.name,
1101
+ agent.description,
1102
+ agent.llm,
1103
+ agent.style,
1104
+ ", ".join(agent.collaborators),
1105
+ ", ".join(agent.tools),
1106
+ ", ".join(agent.knowledge_base),
1107
+ agent.id,
1108
+ )
1109
+ if format == AgentListFormats.Table:
1110
+ output_dictionary["native"] = self._rich_table_to_markdown(native_table)
1111
+ else:
1112
+ rich.print(native_table)
875
1113
 
876
1114
  if kind == AgentKind.EXTERNAL or kind is None:
877
- response = self.get_external_client().get()
878
-
879
- external_agents = []
880
- for agent in response:
881
- try:
882
- external_agents.append(ExternalAgent.model_validate(agent))
883
- except Exception as e:
884
- name = agent.get('name', None)
885
- parse_errors.append([f"External Agent {name} could not be parsed", e])
886
-
887
- response_dict = {agent["id"]: agent for agent in response}
888
-
889
- # Insert config values into config as config object is not retruned from api
890
- for external_agent in external_agents:
891
- if external_agent.id in response_dict:
892
- response_data = response_dict[external_agent.id]
893
- external_agent.config.enable_cot = response_data.get("enable_cot", external_agent.config.enable_cot)
894
- external_agent.config.hidden = response_data.get("hidden", external_agent.config.hidden)
895
-
896
- external_agents_list = []
1115
+ external_agents, new_parse_errors = self._fetch_and_parse_agents(AgentKind.EXTERNAL)
1116
+ parse_errors += new_parse_errors
1117
+
897
1118
  if verbose:
1119
+ external_agents_list = []
898
1120
  for agent in external_agents:
899
1121
  external_agents_list.append(json.loads(agent.dumps_spec()))
900
- verbose_output_dictionary["external"] = external_agents_list
1122
+ output_dictionary["external"] = external_agents_list
901
1123
  else:
902
- external_table = rich.table.Table(
903
- show_header=True,
904
- header_style="bold white",
905
- title="External Agents",
906
- show_lines=True
907
- )
908
- column_args = {
909
- "Name": {"overflow": "fold"},
910
- "Title": {},
911
- "Description": {},
912
- "Tags": {},
913
- "API URL": {"overflow": "fold"},
914
- "Chat Params": {},
915
- "Config": {},
916
- "Nickname": {},
917
- "App ID": {"overflow": "fold"},
918
- "ID": {"overflow": "fold"}
919
- }
920
-
921
- for column in column_args:
922
- external_table.add_column(column, **column_args[column])
1124
+ resolved_external_agents = self._bulk_resolve_agent_app_ids(external_agents)
923
1125
 
924
- for agent in external_agents:
925
- connections_client = get_connections_client()
926
- app_id = connections_client.get_draft_by_id(agent.connection_id)
927
-
928
- external_table.add_row(
929
- agent.name,
930
- agent.title,
931
- agent.description,
932
- ", ".join(agent.tags or []),
933
- agent.api_url,
934
- json.dumps(agent.chat_params),
935
- str(agent.config),
936
- agent.nickname,
937
- app_id,
938
- agent.id
1126
+ if format and format == AgentListFormats.JSON:
1127
+ external_agents_list = []
1128
+ for agent in resolved_external_agents:
1129
+ external_agents_list.append(json.loads(agent.dumps_spec()))
1130
+
1131
+ output_dictionary["external"] = external_agents_list
1132
+ else:
1133
+ external_table = rich.table.Table(
1134
+ show_header=True,
1135
+ header_style="bold white",
1136
+ title="External Agents",
1137
+ show_lines=True
939
1138
  )
940
- rich.print(external_table)
1139
+ column_args = {
1140
+ "Name": {"overflow": "fold"},
1141
+ "Title": {},
1142
+ "Description": {},
1143
+ "Tags": {},
1144
+ "API URL": {"overflow": "fold"},
1145
+ "Chat Params": {},
1146
+ "Config": {},
1147
+ "Nickname": {},
1148
+ "App ID": {"overflow": "fold"},
1149
+ "ID": {"overflow": "fold"}
1150
+ }
1151
+
1152
+ for column in column_args:
1153
+ external_table.add_column(column, **column_args[column])
1154
+
1155
+ for agent in external_agents:
1156
+ connections_client = get_connections_client()
1157
+ app_id = connections_client.get_draft_by_id(agent.connection_id)
1158
+ resolved_native_agents = self._bulk_resolve_agent_app_ids(external_agents)
1159
+
1160
+ external_table.add_row(
1161
+ agent.name,
1162
+ agent.title,
1163
+ agent.description,
1164
+ ", ".join(agent.tags or []),
1165
+ agent.api_url,
1166
+ json.dumps(agent.chat_params),
1167
+ str(agent.config),
1168
+ agent.nickname,
1169
+ app_id,
1170
+ agent.id
1171
+ )
1172
+ if format == AgentListFormats.Table:
1173
+ output_dictionary["external"] = self._rich_table_to_markdown(external_table)
1174
+ else:
1175
+ rich.print(external_table)
941
1176
 
942
1177
  if kind == AgentKind.ASSISTANT or kind is None:
943
- response = self.get_assistant_client().get()
944
-
945
- assistant_agents = []
946
- for agent in response:
947
- try:
948
- assistant_agents.append(AssistantAgent.model_validate(agent))
949
- except Exception as e:
950
- name = agent.get('name', None)
951
- parse_errors.append([f"Assistant Agent {name} could not be parsed", e])
952
-
953
- response_dict = {agent["id"]: agent for agent in response}
954
-
955
- # Insert config values into config as config object is not retruned from api
956
- for assistant_agent in assistant_agents:
957
- if assistant_agent.id in response_dict:
958
- response_data = response_dict[assistant_agent.id]
959
- assistant_agent.config.api_version = response_data.get("api_version", assistant_agent.config.api_version)
960
- assistant_agent.config.assistant_id = response_data.get("assistant_id", assistant_agent.config.assistant_id)
961
- assistant_agent.config.crn = response_data.get("crn", assistant_agent.config.crn)
962
- assistant_agent.config.service_instance_url = response_data.get("service_instance_url", assistant_agent.config.service_instance_url)
963
- assistant_agent.config.environment_id = response_data.get("environment_id", assistant_agent.config.environment_id)
964
- assistant_agent.config.authorization_url = response_data.get("authorization_url", assistant_agent.config.authorization_url)
1178
+ assistant_agents, new_parse_errors = self._fetch_and_parse_agents(AgentKind.ASSISTANT)
1179
+ parse_errors += new_parse_errors
965
1180
 
966
1181
  if verbose:
967
- assistant_agent_specs = []
1182
+ assistant_agents_list = []
968
1183
  for agent in assistant_agents:
969
- assistant_agent_specs.append(json.loads(agent.dumps_spec()))
970
- verbose_output_dictionary["assistant"] = assistant_agent_specs
1184
+ assistant_agents_list.append(json.loads(agent.dumps_spec()))
1185
+ output_dictionary["assistant"] = assistant_agents_list
971
1186
  else:
972
- assistants_table = rich.table.Table(
973
- show_header=True,
974
- header_style="bold white",
975
- title="Assistant Agents",
976
- show_lines=True)
977
- column_args = {
978
- "Name": {"overflow": "fold"},
979
- "Title": {},
980
- "Description": {},
981
- "Tags": {},
982
- "Nickname": {},
983
- "CRN": {},
984
- "Instance URL": {},
985
- "Assistant ID": {"overflow": "fold"},
986
- "Environment ID": {"overflow": "fold"},
987
- "ID": {"overflow": "fold"}
988
- }
989
-
990
- for column in column_args:
991
- assistants_table.add_column(column, **column_args[column])
1187
+ resolved_external_agents = self._bulk_resolve_agent_app_ids(assistant_agents)
992
1188
 
993
- for agent in assistant_agents:
994
- assistants_table.add_row(
995
- agent.name,
996
- agent.title,
997
- agent.description,
998
- ", ".join(agent.tags or []),
999
- agent.nickname,
1000
- agent.config.crn,
1001
- agent.config.service_instance_url,
1002
- agent.config.assistant_id,
1003
- agent.config.environment_id,
1004
- agent.id
1005
- )
1006
- rich.print(assistants_table)
1189
+ if format and format == AgentListFormats.JSON:
1190
+ assistant_agents_list = []
1191
+ for agent in resolved_external_agents:
1192
+ assistant_agents_list.append(json.loads(agent.dumps_spec()))
1193
+
1194
+ output_dictionary["assistant"] = assistant_agents_list
1195
+ else:
1196
+ assistants_table = rich.table.Table(
1197
+ show_header=True,
1198
+ header_style="bold white",
1199
+ title="Assistant Agents",
1200
+ show_lines=True)
1201
+ column_args = {
1202
+ "Name": {"overflow": "fold"},
1203
+ "Title": {},
1204
+ "Description": {},
1205
+ "Tags": {},
1206
+ "Nickname": {},
1207
+ "CRN": {},
1208
+ "Instance URL": {},
1209
+ "Assistant ID": {"overflow": "fold"},
1210
+ "Environment ID": {"overflow": "fold"},
1211
+ "ID": {"overflow": "fold"}
1212
+ }
1213
+
1214
+ for column in column_args:
1215
+ assistants_table.add_column(column, **column_args[column])
1216
+
1217
+ for agent in assistant_agents:
1218
+ assistants_table.add_row(
1219
+ agent.name,
1220
+ agent.title,
1221
+ agent.description,
1222
+ ", ".join(agent.tags or []),
1223
+ agent.nickname,
1224
+ agent.config.crn,
1225
+ agent.config.service_instance_url,
1226
+ agent.config.assistant_id,
1227
+ agent.config.environment_id,
1228
+ agent.id
1229
+ )
1230
+ if format == AgentListFormats.Table:
1231
+ output_dictionary["assistant"] = self._rich_table_to_markdown(assistants_table)
1232
+ else:
1233
+ rich.print(assistants_table)
1007
1234
 
1008
1235
  if verbose:
1009
- rich.print_json(data=verbose_output_dictionary)
1236
+ rich.print_json(data=output_dictionary)
1010
1237
 
1011
1238
  for error in parse_errors:
1012
1239
  for l in error:
1013
1240
  logger.error(l)
1241
+
1242
+ if verbose or format:
1243
+ return output_dictionary
1244
+
1014
1245
 
1015
1246
  def remove_agent(self, name: str, kind: AgentKind):
1016
1247
  try:
@@ -327,7 +327,11 @@ def talk_to_cpe(cpe_client, samples_file=None, context_data=None):
327
327
 
328
328
 
329
329
  def prompt_tune(agent_spec: str, output_file: str | None, samples_file: str | None, dry_run_flag: bool) -> None:
330
- agent = AgentsController.import_agent(file=agent_spec, app_id=None)[0]
330
+ agents = AgentsController.import_agent(file=agent_spec, app_id=None)
331
+ if not agents:
332
+ logger.error("Invalid agent spec file provided, no agent found.")
333
+ sys.exit(1)
334
+ agent = agents[0]
331
335
  agent_kind = agent.kind
332
336
 
333
337
  if agent_kind != AgentKind.NATIVE:
@@ -342,7 +346,7 @@ def prompt_tune(agent_spec: str, output_file: str | None, samples_file: str | No
342
346
 
343
347
  client = get_cpe_client()
344
348
 
345
- instr = agent.instructions
349
+ instr = agent.instructions if agent.instructions else ""
346
350
 
347
351
  tools = _get_tools_from_names(agent.tools)
348
352
 
@@ -70,7 +70,7 @@ def add_env(
70
70
  ] = None,
71
71
  type: Annotated[
72
72
  EnvironmentAuthType,
73
- typer.Option("--type", "-t", help="The type of auth you wish to use"),
73
+ typer.Option("--type", "-t", help="The type of auth you wish to use. This overrides the auth type that is inferred from the url"),
74
74
  ] = None,
75
75
  insecure: Annotated[
76
76
  bool,