ibm-watsonx-orchestrate 1.3.0__tar.gz → 1.4.2__tar.gz

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 (117) hide show
  1. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/PKG-INFO +4 -1
  2. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/pyproject.toml +4 -1
  3. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/__init__.py +1 -1
  4. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/agents/types.py +2 -0
  5. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/knowledge_bases/types.py +9 -2
  6. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/agent_builder/toolkits/base_toolkit.py +32 -0
  7. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/agent_builder/toolkits/types.py +42 -0
  8. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/tools/openapi_tool.py +10 -1
  9. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/tools/python_tool.py +4 -2
  10. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/tools/types.py +2 -1
  11. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/agents/agents_command.py +29 -0
  12. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +271 -12
  13. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_controller.py +17 -2
  14. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/cli/commands/models/env_file_model_provider_mapper.py +180 -0
  15. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/cli/commands/models/models_command.py +314 -0
  16. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/server/server_command.py +117 -48
  17. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/cli/commands/server/types.py +105 -0
  18. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_command.py +119 -0
  19. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_controller.py +123 -42
  20. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/tools/tools_command.py +22 -1
  21. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +197 -12
  22. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/agents/agent_client.py +4 -1
  23. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/agents/assistant_agent_client.py +5 -1
  24. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/agents/external_agent_client.py +5 -1
  25. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/analytics/llm/analytics_llm_client.py +2 -6
  26. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/base_api_client.py +5 -2
  27. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/connections/connections_client.py +3 -9
  28. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/client/model_policies/model_policies_client.py +47 -0
  29. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/client/model_policies/types.py +36 -0
  30. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/client/models/models_client.py +46 -0
  31. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/client/models/types.py +177 -0
  32. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/toolkit/toolkit_client.py +15 -6
  33. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/client/tools/tempus_client.py +40 -0
  34. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/tools/tool_client.py +8 -0
  35. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/docker/compose-lite.yml +68 -13
  36. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/docker/default.env +22 -12
  37. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/docker/tempus/common-config.yaml +1 -0
  38. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/experimental/flow_builder/flows/__init__.py +41 -0
  39. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/experimental/flow_builder/flows/constants.py +17 -0
  40. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/experimental/flow_builder/flows/data_map.py +91 -0
  41. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/experimental/flow_builder/flows/decorators.py +143 -0
  42. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/experimental/flow_builder/flows/events.py +72 -0
  43. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/experimental/flow_builder/flows/flow.py +1288 -0
  44. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/experimental/flow_builder/node.py +97 -0
  45. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/experimental/flow_builder/resources/flow_status.openapi.yml +98 -0
  46. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/experimental/flow_builder/types.py +492 -0
  47. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/experimental/flow_builder/utils.py +113 -0
  48. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/run/__init__.py +0 -0
  49. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/utils/__init__.py +0 -0
  50. ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/utils/logging/__init__.py +0 -0
  51. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/utils/utils.py +5 -2
  52. ibm_watsonx_orchestrate-1.3.0/src/ibm_watsonx_orchestrate/cli/commands/models/models_command.py +0 -128
  53. ibm_watsonx_orchestrate-1.3.0/src/ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_command.py +0 -71
  54. ibm_watsonx_orchestrate-1.3.0/src/ibm_watsonx_orchestrate/docker/tempus/common-config.yaml +0 -1
  55. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/.gitignore +0 -0
  56. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/LICENSE +0 -0
  57. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/__init__.py +0 -0
  58. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/agents/__init__.py +0 -0
  59. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/agents/agent.py +0 -0
  60. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/agents/assistant_agent.py +0 -0
  61. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/agents/external_agent.py +0 -0
  62. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/connections/__init__.py +0 -0
  63. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/connections/connections.py +0 -0
  64. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/connections/types.py +0 -0
  65. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/knowledge_bases/knowledge_base.py +0 -0
  66. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/knowledge_bases/knowledge_base_requests.py +0 -0
  67. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/tools/__init__.py +0 -0
  68. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/tools/base_tool.py +0 -0
  69. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/utils/__init__.py +0 -0
  70. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/agent_builder/utils/pydantic_utils.py +0 -0
  71. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/__init__.py +0 -0
  72. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/__init__.py +0 -0
  73. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/channels/channels_command.py +0 -0
  74. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/channels/channels_controller.py +0 -0
  75. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/channels/types.py +0 -0
  76. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/channels/webchat/channels_webchat_command.py +0 -0
  77. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/channels/webchat/channels_webchat_controller.py +0 -0
  78. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/chat/chat_command.py +0 -0
  79. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/connections/connections_command.py +0 -0
  80. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +0 -0
  81. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/environment/environment_command.py +0 -0
  82. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/environment/environment_controller.py +0 -0
  83. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/environment/types.py +0 -0
  84. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_command.py +0 -0
  85. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/login/login_command.py +0 -0
  86. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/settings/__init__.py +0 -0
  87. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/settings/observability/__init__.py +0 -0
  88. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/settings/observability/langfuse/__init__.py +0 -0
  89. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/settings/observability/langfuse/langfuse_command.py +0 -0
  90. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/settings/observability/observability_command.py +0 -0
  91. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/settings/settings_command.py +0 -0
  92. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/commands/tools/types.py +0 -0
  93. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/config.py +0 -0
  94. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/init_helper.py +0 -0
  95. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/cli/main.py +0 -0
  96. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/__init__.py +0 -0
  97. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/analytics/__init__.py +0 -0
  98. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/analytics/llm/__init__.py +0 -0
  99. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/base_service_instance.py +0 -0
  100. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/client.py +0 -0
  101. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/client_errors.py +0 -0
  102. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/connections/__init__.py +0 -0
  103. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/connections/utils.py +0 -0
  104. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/credentials.py +0 -0
  105. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/knowledge_bases/knowledge_base_client.py +0 -0
  106. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/local_service_instance.py +0 -0
  107. {ibm_watsonx_orchestrate-1.3.0/src/ibm_watsonx_orchestrate/run → ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/client/model_policies}/__init__.py +0 -0
  108. {ibm_watsonx_orchestrate-1.3.0/src/ibm_watsonx_orchestrate/utils → ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/client/models}/__init__.py +0 -0
  109. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/service_instance.py +0 -0
  110. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/client/utils.py +0 -0
  111. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/docker/sdk/ibm_watsonx_orchestrate-0.6.0-py3-none-any.whl +0 -0
  112. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/docker/sdk/ibm_watsonx_orchestrate-0.6.0.tar.gz +0 -0
  113. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/docker/start-up.sh +0 -0
  114. {ibm_watsonx_orchestrate-1.3.0/src/ibm_watsonx_orchestrate/utils/logging → ibm_watsonx_orchestrate-1.4.2/src/ibm_watsonx_orchestrate/experimental/flow_builder}/__init__.py +0 -0
  115. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/run/connections.py +0 -0
  116. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/utils/logging/logger.py +0 -0
  117. {ibm_watsonx_orchestrate-1.3.0 → ibm_watsonx_orchestrate-1.4.2}/src/ibm_watsonx_orchestrate/utils/logging/logging.yaml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ibm-watsonx-orchestrate
3
- Version: 1.3.0
3
+ Version: 1.4.2
4
4
  Summary: IBM watsonx.orchestrate SDK
5
5
  Author-email: IBM <support@ibm.com>
6
6
  License: MIT License
@@ -14,12 +14,15 @@ Requires-Dist: ibm-cloud-sdk-core>=3.22.0
14
14
  Requires-Dist: jsonref==1.1.0
15
15
  Requires-Dist: jsonschema<5.0.0,>=4.23.0
16
16
  Requires-Dist: langchain-community<1.0.0,>=0.3.12
17
+ Requires-Dist: munch>=4.0.0
17
18
  Requires-Dist: numpy>=1.26.0
18
19
  Requires-Dist: packaging>=24.2
19
20
  Requires-Dist: pydantic<3.0.0,>=2.10.3
20
21
  Requires-Dist: pyjwt<3.0.0,>=2.10.1
21
22
  Requires-Dist: python-dotenv>=1.0.0
23
+ Requires-Dist: pytz>=2025.2
22
24
  Requires-Dist: pyyaml<7.0.0,>=6.0.2
25
+ Requires-Dist: redis>=6.0.0
23
26
  Requires-Dist: requests>=2.32.0
24
27
  Requires-Dist: rich<14.0.0,>=13.9.4
25
28
  Requires-Dist: typer<1.0.0,>=0.15.1
@@ -33,7 +33,10 @@ dependencies = [
33
33
  "requests>=2.32.0",
34
34
  "rich>=13.9.4,<14.0.0",
35
35
  "typer>=0.15.1,<1.0.0",
36
- "urllib3>=2.2.3"
36
+ "urllib3>=2.2.3",
37
+ "munch>=4.0.0",
38
+ "pytz>=2025.2",
39
+ "redis>=6.0.0"
37
40
  ]
38
41
 
39
42
  [project.optional-dependencies]
@@ -5,7 +5,7 @@
5
5
 
6
6
  pkg_name = "ibm-watsonx-orchestrate"
7
7
 
8
- __version__ = "1.3.0"
8
+ __version__ = "1.4.2"
9
9
 
10
10
 
11
11
 
@@ -46,6 +46,7 @@ class BaseAgentSpec(BaseModel):
46
46
  kind: AgentKind
47
47
  id: Optional[Annotated[str, Field(json_schema_extra={"min_length_str": 1})]] = None
48
48
  name: Annotated[str, Field(json_schema_extra={"min_length_str":1})]
49
+ display_name: Annotated[Optional[str], Field(json_schema_extra={"min_length_str":1})] = None
49
50
  description: Annotated[str, Field(json_schema_extra={"min_length_str":1})]
50
51
 
51
52
  def dump_spec(self, file: str) -> None:
@@ -69,6 +70,7 @@ class BaseAgentSpec(BaseModel):
69
70
  class AgentStyle(str, Enum):
70
71
  DEFAULT = "default"
71
72
  REACT = "react"
73
+ PLANNER = "planner"
72
74
 
73
75
  class AgentSpec(BaseAgentSpec):
74
76
  model_config = ConfigDict(arbitrary_types_allowed=True)
@@ -3,8 +3,7 @@ from datetime import datetime
3
3
  from uuid import UUID
4
4
  from enum import Enum
5
5
 
6
- from pydantic import BaseModel, Field
7
-
6
+ from pydantic import BaseModel, model_validator
8
7
 
9
8
  class SpecVersion(str, Enum):
10
9
  V1 = "v1"
@@ -213,6 +212,14 @@ class PatchKnowledgeBase(BaseModel):
213
212
  conversational_search_tool: Optional[ConversationalSearchConfig] = None
214
213
  prioritize_built_in_index: Optional[bool] = None
215
214
  representation: Optional[KnowledgeBaseRepresentation] = None
215
+
216
+ @model_validator(mode="after")
217
+ def validate_fields(self):
218
+ if self.documents and self.conversational_search_tool and self.conversational_search_tool.index_config:
219
+ raise ValueError("Must not provide both \"documents\" or \"conversational_search_tool.index_config\"")
220
+ if self.conversational_search_tool and self.conversational_search_tool.index_config and len(self.conversational_search_tool.index_config) != 1:
221
+ raise ValueError(f"Must provide exactly one conversational_search_tool.index_config. Provided {len(self.conversational_search_tool.index_config)}.")
222
+ return self
216
223
 
217
224
  class KnowledgeBaseSpec(BaseModel):
218
225
  """Schema for a complete knowledge-base."""
@@ -0,0 +1,32 @@
1
+ import json
2
+
3
+ import yaml
4
+
5
+ from .types import ToolkitSpec
6
+
7
+
8
+ class BaseToolkit:
9
+ __toolkit_spec__: ToolkitSpec
10
+
11
+ def __init__(self, spec: ToolkitSpec):
12
+ self.__toolkit_spec__ = spec
13
+
14
+ def __call__(self, **kwargs):
15
+ pass
16
+
17
+ def dump_spec(self, file: str) -> None:
18
+ dumped = self.__toolkit_spec__.model_dump(mode='json', exclude_unset=True, exclude_none=True, by_alias=True)
19
+ with open(file, 'w') as f:
20
+ if file.endswith('.yaml') or file.endswith('.yml'):
21
+ yaml.dump(dumped, f)
22
+ elif file.endswith('.json'):
23
+ json.dump(dumped, f, indent=2)
24
+ else:
25
+ raise ValueError('file must end in .json, .yaml, or .yml')
26
+
27
+ def dumps_spec(self) -> str:
28
+ dumped = self.__toolkit_spec__.model_dump(mode='json', exclude_unset=True, exclude_none=True, by_alias=True)
29
+ return json.dumps(dumped, indent=2)
30
+
31
+ def __repr__(self):
32
+ return f"Toolkit(name='{self.__toolkit_spec__.name}', description='{self.__toolkit_spec__.description}')"
@@ -0,0 +1,42 @@
1
+ from typing import List, Dict, Optional
2
+ from enum import Enum
3
+ from pydantic import BaseModel, model_validator
4
+
5
+ class ToolkitKind(str, Enum):
6
+ MCP = "mcp"
7
+
8
+ class Language(str, Enum):
9
+ NODE = "node"
10
+ PYTHON ="python"
11
+
12
+ class ToolkitSource(str, Enum):
13
+ FILES = "files"
14
+ PUBLIC_REGISTRY = "public-registry"
15
+
16
+
17
+
18
+ class McpModel(BaseModel):
19
+ source: str
20
+ command: str
21
+ args: List[str]
22
+ tools: List[str]
23
+ connections: Dict[str, str]
24
+
25
+
26
+ class ToolkitSpec(BaseModel):
27
+ id: str
28
+ tenant_id: str
29
+ name: str
30
+ description: Optional[str]
31
+ created_on: str
32
+ updated_at: str
33
+ created_by: str
34
+ created_by_username: str
35
+ tools: List[str] | None
36
+ mcp: McpModel
37
+
38
+ @model_validator(mode='after')
39
+ def validate_tools_and_mcp(self) -> 'ToolkitSpec':
40
+ if self.mcp.source not in {"files", "public-registry"}:
41
+ raise ValueError("MCP source must be either 'files' or 'public-registry'.")
42
+ return self
@@ -293,7 +293,7 @@ async def create_openapi_json_tool_from_uri(
293
293
  description=description,
294
294
  input_schema=input_schema,
295
295
  output_schema=output_schema,
296
- app_id=app_id
296
+ connection_id=app_id
297
297
  )
298
298
 
299
299
 
@@ -302,6 +302,15 @@ async def create_openapi_json_tools_from_uri(
302
302
  connection_id: str = None
303
303
  ) -> List[OpenAPITool]:
304
304
  openapi_contents = await _get_openapi_spec_from_uri(openapi_uri)
305
+ tools: List[OpenAPITool] = await create_openapi_json_tools_from_content(openapi_contents, connection_id)
306
+
307
+ return tools
308
+
309
+ async def create_openapi_json_tools_from_content(
310
+ openapi_contents: dict,
311
+ connection_id: str = None
312
+ ) -> List[OpenAPITool]:
313
+
305
314
  tools: List[OpenAPITool] = []
306
315
 
307
316
  for path, methods in openapi_contents.get('paths', {}).items():
@@ -47,7 +47,7 @@ class PythonTool(BaseTool):
47
47
  return PythonTool(fn=fn, spec=spec)
48
48
 
49
49
  def __repr__(self):
50
- return f"PythonTool(fn={self.__tool_spec__.binding.python.function}, name='{self.__tool_spec__.name}', description='{self.__tool_spec__.description}')"
50
+ return f"PythonTool(fn={self.__tool_spec__.binding.python.function}, name='{self.__tool_spec__.name}', display_name='{self.__tool_spec__.display_name or ''}', description='{self.__tool_spec__.description}')"
51
51
 
52
52
  def __str__(self):
53
53
  return self.__repr__()
@@ -99,7 +99,8 @@ def tool(
99
99
  input_schema: ToolRequestBody = None,
100
100
  output_schema: ToolResponseBody = None,
101
101
  permission: ToolPermission = ToolPermission.READ_ONLY,
102
- expected_credentials: List[ExpectedCredentials] = None
102
+ expected_credentials: List[ExpectedCredentials] = None,
103
+ display_name: str = None
103
104
  ) -> Callable[[{__name__, __doc__}], PythonTool]:
104
105
  """
105
106
  Decorator to convert a python function into a callable tool.
@@ -125,6 +126,7 @@ def tool(
125
126
 
126
127
  spec = ToolSpec(
127
128
  name=name or fn.__name__,
129
+ display_name=display_name,
128
130
  description=_desc,
129
131
  permission=permission
130
132
  )
@@ -137,7 +137,7 @@ class ClientSideToolBinding(BaseModel):
137
137
  class McpToolBinding(BaseModel):
138
138
  server_url: Optional[str] = None
139
139
  source: str
140
- connections: Dict[str, str]
140
+ connections: Dict[str, str] | None
141
141
 
142
142
  class ToolBinding(BaseModel):
143
143
  openapi: OpenApiToolBinding = None
@@ -166,6 +166,7 @@ class ToolBinding(BaseModel):
166
166
 
167
167
  class ToolSpec(BaseModel):
168
168
  name: str
169
+ display_name: str | None = None
169
170
  description: str
170
171
  permission: ToolPermission
171
172
  input_schema: ToolRequestBody = None
@@ -190,3 +190,32 @@ def remove_agent(
190
190
  ):
191
191
  agents_controller = AgentsController()
192
192
  agents_controller.remove_agent(name=name, kind=kind)
193
+
194
+ @agents_app.command(name="export", help='Export an agent and its dependencies to a zip file or yaml')
195
+ def export_agent(
196
+ name: Annotated[
197
+ str,
198
+ typer.Option("--name", "-n", help="Name of the agent you wish to export"),
199
+ ],
200
+ kind: Annotated[
201
+ AgentKind,
202
+ typer.Option("--kind", "-k", help="The kind of agent you wish to export"),
203
+ ],
204
+ output_file: Annotated[
205
+ str,
206
+ typer.Option(
207
+ "--output",
208
+ "-o",
209
+ help="Path to a where the file containing the exported data should be saved",
210
+ ),
211
+ ],
212
+ agent_only_flag: Annotated[
213
+ bool,
214
+ typer.Option(
215
+ "--agent-only",
216
+ help="Export only the yaml to the specified agent, excluding its dependencies",
217
+ ),
218
+ ]=False
219
+ ):
220
+ agents_controller = AgentsController()
221
+ agents_controller.export_agent(name=name, kind=kind, output_path=output_file, agent_only_flag=agent_only_flag)
@@ -4,13 +4,15 @@ import rich
4
4
  import requests
5
5
  import importlib
6
6
  import inspect
7
+ import zipfile
7
8
  import sys
9
+ import io
8
10
  import logging
9
11
  from pathlib import Path
10
12
  from copy import deepcopy
11
13
 
12
14
  from typing import Iterable, List
13
- from ibm_watsonx_orchestrate.cli.commands.tools.tools_controller import import_python_tool
15
+ from ibm_watsonx_orchestrate.cli.commands.tools.tools_controller import import_python_tool, ToolsController
14
16
  from ibm_watsonx_orchestrate.cli.commands.knowledge_bases.knowledge_bases_controller import import_python_knowledge_base
15
17
 
16
18
  from ibm_watsonx_orchestrate.agent_builder.agents import (
@@ -28,6 +30,7 @@ from ibm_watsonx_orchestrate.client.connections import get_connections_client
28
30
  from ibm_watsonx_orchestrate.client.knowledge_bases.knowledge_base_client import KnowledgeBaseClient
29
31
 
30
32
  from ibm_watsonx_orchestrate.client.utils import instantiate_client
33
+ from ibm_watsonx_orchestrate.utils.utils import check_file_in_zip
31
34
 
32
35
  logger = logging.getLogger(__name__)
33
36
 
@@ -142,10 +145,29 @@ def get_conn_id_from_app_id(app_id: str) -> str:
142
145
  connections_client = get_connections_client()
143
146
  connection = connections_client.get_draft_by_app_id(app_id=app_id)
144
147
  if not connection:
145
- logger.error(f"No connection exits with the app-id '{app_id}'")
148
+ logger.error(f"No connection exists with the app-id '{app_id}'")
146
149
  exit(1)
147
150
  return connection.connection_id
148
151
 
152
+ def get_app_id_from_conn_id(conn_id: str) -> str:
153
+ connections_client = get_connections_client()
154
+ app_id = connections_client.get_draft_by_id(conn_id=conn_id)
155
+ if not app_id or app_id == conn_id:
156
+ logger.error(f"No connection exists with the connection id '{conn_id}'")
157
+ exit(1)
158
+ return app_id
159
+
160
+ def get_agent_details(name: str, client: AgentClient | ExternalAgentClient | AssistantAgentClient) -> dict:
161
+ agent_specs = client.get_draft_by_name(name)
162
+ if len(agent_specs) > 1:
163
+ logger.error(f"Multiple agents with the name '{name}' found. Failed to get agent")
164
+ sys.exit(1)
165
+ if len(agent_specs) == 0:
166
+ logger.error(f"No agents with the name '{name}' found. Failed to get agent")
167
+ sys.exit(1)
168
+
169
+ return agent_specs[0]
170
+
149
171
  class AgentsController:
150
172
  def __init__(self):
151
173
  self.native_client = None
@@ -227,6 +249,7 @@ class AgentsController:
227
249
  matching_external_agents = external_client.get_drafts_by_names(deref_agent.collaborators)
228
250
  matching_assistant_agents = assistant_client.get_drafts_by_names(deref_agent.collaborators)
229
251
  matching_agents = matching_native_agents + matching_external_agents + matching_assistant_agents
252
+
230
253
  name_id_lookup = {}
231
254
  for a in matching_agents:
232
255
  if a.get("name") in name_id_lookup:
@@ -245,6 +268,35 @@ class AgentsController:
245
268
 
246
269
  return deref_agent
247
270
 
271
+ def reference_collaborators(self, agent: Agent) -> Agent:
272
+ native_client = self.get_native_client()
273
+ external_client = self.get_external_client()
274
+ assistant_client = self.get_assistant_client()
275
+
276
+ ref_agent = deepcopy(agent)
277
+ matching_native_agents = native_client.get_drafts_by_ids(ref_agent.collaborators)
278
+ matching_external_agents = external_client.get_drafts_by_ids(ref_agent.collaborators)
279
+ matching_assistant_agents = assistant_client.get_drafts_by_ids(ref_agent.collaborators)
280
+ matching_agents = matching_native_agents + matching_external_agents + matching_assistant_agents
281
+
282
+ id_name_lookup = {}
283
+ for a in matching_agents:
284
+ if a.get("id") in id_name_lookup:
285
+ logger.error(f"Duplicate draft entries for collaborator '{a.get('id')}'")
286
+ sys.exit(1)
287
+ id_name_lookup[a.get("id")] = a.get("name")
288
+
289
+ ref_collaborators = []
290
+ for id in agent.collaborators:
291
+ name = id_name_lookup.get(id)
292
+ if not name:
293
+ logger.error(f"Failed to find collaborator. No agents found with the id '{id}'")
294
+ sys.exit(1)
295
+ ref_collaborators.append(name)
296
+ ref_agent.collaborators = ref_collaborators
297
+
298
+ return ref_agent
299
+
248
300
  def dereference_tools(self, agent: Agent) -> Agent:
249
301
  tool_client = self.get_tool_client()
250
302
 
@@ -254,7 +306,7 @@ class AgentsController:
254
306
  name_id_lookup = {}
255
307
  for tool in matching_tools:
256
308
  if tool.get("name") in name_id_lookup:
257
- logger.error(f"Duplicate draft entries for tol '{tool.get('name')}'")
309
+ logger.error(f"Duplicate draft entries for tool '{tool.get('name')}'")
258
310
  sys.exit(1)
259
311
  name_id_lookup[tool.get("name")] = tool.get("id")
260
312
 
@@ -269,6 +321,30 @@ class AgentsController:
269
321
 
270
322
  return deref_agent
271
323
 
324
+ def reference_tools(self, agent: Agent) -> Agent:
325
+ tool_client = self.get_tool_client()
326
+
327
+ ref_agent = deepcopy(agent)
328
+ matching_tools = tool_client.get_drafts_by_ids(ref_agent.tools)
329
+
330
+ id_name_lookup = {}
331
+ for tool in matching_tools:
332
+ if tool.get("id") in id_name_lookup:
333
+ logger.error(f"Duplicate draft entries for tool '{tool.get('id')}'")
334
+ sys.exit(1)
335
+ id_name_lookup[tool.get("id")] = tool.get("name")
336
+
337
+ ref_tools = []
338
+ for id in agent.tools:
339
+ name = id_name_lookup[id]
340
+ if not name:
341
+ logger.error(f"Failed to find tool. No tools found with the id '{id}'")
342
+ sys.exit(1)
343
+ ref_tools.append(name)
344
+ ref_agent.tools = ref_tools
345
+
346
+ return ref_agent
347
+
272
348
  def dereference_knowledge_bases(self, agent: Agent) -> Agent:
273
349
  client = self.get_knowledge_base_client()
274
350
 
@@ -293,6 +369,22 @@ class AgentsController:
293
369
 
294
370
  return deref_agent
295
371
 
372
+ def reference_knowledge_bases(self, agent: Agent) -> Agent:
373
+ client = self.get_knowledge_base_client()
374
+
375
+ ref_agent = deepcopy(agent)
376
+
377
+ ref_knowledge_bases = []
378
+ for id in agent.knowledge_base:
379
+ matching_knowledge_base = client.get_by_id(id)
380
+ name = matching_knowledge_base.get("name")
381
+ if not name:
382
+ logger.error(f"Failed to find knowledge base. No knowledge base found with the id '{id}'")
383
+ sys.exit(1)
384
+ ref_knowledge_bases.append(name)
385
+ ref_agent.knowledge_base = ref_knowledge_bases
386
+ return ref_agent
387
+
296
388
  @staticmethod
297
389
  def dereference_app_id(agent: ExternalAgent | AssistantAgent) -> ExternalAgent | AssistantAgent:
298
390
  if agent.kind == AgentKind.EXTERNAL:
@@ -301,6 +393,17 @@ class AgentsController:
301
393
  agent.config.connection_id = get_conn_id_from_app_id(agent.config.app_id)
302
394
 
303
395
  return agent
396
+
397
+ @staticmethod
398
+ def reference_app_id(agent: ExternalAgent | AssistantAgent) -> ExternalAgent | AssistantAgent:
399
+ if agent.kind == AgentKind.EXTERNAL:
400
+ agent.app_id = get_app_id_from_conn_id(agent.connection_id)
401
+ agent.connection_id = None
402
+ else:
403
+ agent.config.app_id = get_app_id_from_conn_id(agent.config.connection_id)
404
+ agent.config.connection_id = None
405
+
406
+ return agent
304
407
 
305
408
 
306
409
  def dereference_native_agent_dependencies(self, agent: Agent) -> Agent:
@@ -313,6 +416,16 @@ class AgentsController:
313
416
 
314
417
  return agent
315
418
 
419
+ def reference_native_agent_dependencies(self, agent: Agent) -> Agent:
420
+ if agent.collaborators and len(agent.collaborators):
421
+ agent = self.reference_collaborators(agent)
422
+ if agent.tools and len(agent.tools):
423
+ agent = self.reference_tools(agent)
424
+ if agent.knowledge_base and len(agent.knowledge_base):
425
+ agent = self.reference_knowledge_bases(agent)
426
+
427
+ return agent
428
+
316
429
  def dereference_external_or_assistant_agent_dependencies(self, agent: ExternalAgent | AssistantAgent) -> ExternalAgent | AssistantAgent:
317
430
  agent_dict = agent.model_dump()
318
431
 
@@ -320,13 +433,28 @@ class AgentsController:
320
433
  agent = self.dereference_app_id(agent)
321
434
 
322
435
  return agent
323
-
324
- def dereference_agent_dependencies(self, agent: Agent ) -> Agent | ExternalAgent | AssistantAgent:
436
+
437
+ def reference_external_or_assistant_agent_dependencies(self, agent: ExternalAgent | AssistantAgent) -> ExternalAgent | AssistantAgent:
438
+ agent_dict = agent.model_dump()
439
+
440
+ if agent_dict.get("connection_id") or agent.config.model_dump().get("connection_id"):
441
+ agent = self.reference_app_id(agent)
442
+
443
+ return agent
444
+
445
+ # Convert all names used in an agent to the corresponding ids
446
+ def dereference_agent_dependencies(self, agent: Agent | ExternalAgent | AssistantAgent ) -> Agent | ExternalAgent | AssistantAgent:
325
447
  if isinstance(agent, Agent):
326
448
  return self.dereference_native_agent_dependencies(agent)
327
449
  if isinstance(agent, ExternalAgent) or isinstance(agent, AssistantAgent):
328
450
  return self.dereference_external_or_assistant_agent_dependencies(agent)
329
-
451
+
452
+ # Convert all ids used in an agent to the corresponding names
453
+ def reference_agent_dependencies(self, agent: Agent | ExternalAgent | AssistantAgent ) -> Agent | ExternalAgent | AssistantAgent:
454
+ if isinstance(agent, Agent):
455
+ return self.reference_native_agent_dependencies(agent)
456
+ if isinstance(agent, ExternalAgent) or isinstance(agent, AssistantAgent):
457
+ return self.reference_external_or_assistant_agent_dependencies(agent)
330
458
 
331
459
  def publish_or_update_agents(
332
460
  self, agents: Iterable[Agent]
@@ -368,13 +496,13 @@ class AgentsController:
368
496
 
369
497
  def publish_agent(self, agent: Agent, **kwargs) -> None:
370
498
  if isinstance(agent, Agent):
371
- self.get_native_client().create(agent.model_dump())
499
+ self.get_native_client().create(agent.model_dump(exclude_none=True))
372
500
  logger.info(f"Agent '{agent.name}' imported successfully")
373
501
  if isinstance(agent, ExternalAgent):
374
- self.get_external_client().create(agent.model_dump())
502
+ self.get_external_client().create(agent.model_dump(exclude_none=True))
375
503
  logger.info(f"External Agent '{agent.name}' imported successfully")
376
504
  if isinstance(agent, AssistantAgent):
377
- self.get_assistant_client().create(agent.model_dump(by_alias=True))
505
+ self.get_assistant_client().create(agent.model_dump(exclude_none=True, by_alias=True))
378
506
  logger.info(f"Assistant Agent '{agent.name}' imported successfully")
379
507
 
380
508
  def update_agent(
@@ -382,15 +510,15 @@ class AgentsController:
382
510
  ) -> None:
383
511
  if isinstance(agent, Agent):
384
512
  logger.info(f"Existing Agent '{agent.name}' found. Updating...")
385
- self.get_native_client().update(agent_id, agent.model_dump())
513
+ self.get_native_client().update(agent_id, agent.model_dump(exclude_none=True))
386
514
  logger.info(f"Agent '{agent.name}' updated successfully")
387
515
  if isinstance(agent, ExternalAgent):
388
516
  logger.info(f"Existing External Agent '{agent.name}' found. Updating...")
389
- self.get_external_client().update(agent_id, agent.model_dump())
517
+ self.get_external_client().update(agent_id, agent.model_dump(exclude_none=True))
390
518
  logger.info(f"External Agent '{agent.name}' updated successfully")
391
519
  if isinstance(agent, AssistantAgent):
392
520
  logger.info(f"Existing Assistant Agent '{agent.name}' found. Updating...")
393
- self.get_assistant_client().update(agent_id, agent.model_dump(by_alias=True))
521
+ self.get_assistant_client().update(agent_id, agent.model_dump(exclude_none=True, by_alias=True))
394
522
  logger.info(f"Assistant Agent '{agent.name}' updated successfully")
395
523
 
396
524
  @staticmethod
@@ -659,4 +787,135 @@ class AgentsController:
659
787
  except requests.HTTPError as e:
660
788
  logger.error(e.response.text)
661
789
  exit(1)
790
+
791
+ def get_spec_file_content(self, agent: Agent | ExternalAgent | AssistantAgent):
792
+ ref_agent = self.reference_agent_dependencies(agent)
793
+ agent_spec = ref_agent.model_dump(mode='json', exclude_none=True)
794
+ return agent_spec
795
+
796
+ def get_agent(self, name: str, kind: AgentKind) -> Agent | ExternalAgent | AssistantAgent:
797
+ match kind:
798
+ case AgentKind.NATIVE:
799
+ client = self.get_native_client()
800
+ agent_details = get_agent_details(name=name, client=client)
801
+ agent = Agent.model_validate(agent_details)
802
+ case AgentKind.EXTERNAL:
803
+ client = self.get_external_client()
804
+ agent_details = get_agent_details(name=name, client=client)
805
+ agent = ExternalAgent.model_validate(agent_details)
806
+ case AgentKind.ASSISTANT:
807
+ client = self.get_assistant_client()
808
+ agent_details = get_agent_details(name=name, client=client)
809
+ agent = AssistantAgent.model_validate(agent_details)
810
+
811
+ return agent
812
+
813
+ def get_agent_by_id(self, id: str) -> Agent | ExternalAgent | AssistantAgent:
814
+ native_client = self.get_native_client()
815
+ external_client = self.get_external_client()
816
+ assistant_client = self.get_assistant_client()
817
+
818
+ native_result = native_client.get_draft_by_id(id)
819
+ external_result = external_client.get_draft_by_id(id)
820
+ assistant_result = assistant_client.get_draft_by_id(id)
821
+
822
+ if native_result:
823
+ return Agent.model_validate(native_result)
824
+ if external_result:
825
+ return ExternalAgent.model_validate(external_result)
826
+ if assistant_result:
827
+ return AssistantAgent.model_validate(assistant_result)
828
+
829
+
830
+ def export_agent(self, name: str, kind: AgentKind, output_path: str, agent_only_flag: bool=False, zip_file_out: zipfile.ZipFile | None = None) -> None:
831
+
832
+ output_file = Path(output_path)
833
+ output_file_extension = output_file.suffix
834
+ output_file_name = output_file.stem
835
+ if not agent_only_flag and output_file_extension != ".zip":
836
+ logger.error(f"Output file must end with the extension '.zip'. Provided file '{output_path}' ends with '{output_file_extension}'")
837
+ sys.exit(1)
838
+ elif agent_only_flag and (output_file_extension != ".yaml" and output_file_extension != ".yml"):
839
+ logger.error(f"Output file must end with the extension '.yaml' or '.yml'. Provided file '{output_path}' ends with '{output_file_extension}'")
840
+ sys.exit(1)
841
+
842
+ agent = self.get_agent(name, kind)
843
+ agent_spec_file_content = self.get_spec_file_content(agent)
844
+
845
+ agent_spec_file_content.pop("hidden", None)
846
+ agent_spec_file_content.pop("id", None)
847
+ agent_spec_file_content["spec_version"] = SpecVersion.V1.value
848
+
849
+ if agent_only_flag:
850
+ logger.info(f"Exported agent definition for '{name}' to '{output_path}'")
851
+ with open(output_path, 'w') as outfile:
852
+ yaml.dump(agent_spec_file_content, outfile, sort_keys=False, default_flow_style=False)
853
+ return
854
+
855
+ close_file_flag = False
856
+ if zip_file_out is None:
857
+ close_file_flag = True
858
+ zip_file_out = zipfile.ZipFile(output_path, "w")
859
+
860
+ logger.info(f"Exporting agent definition for '{name}'")
861
+
862
+ agent_spec_yaml = yaml.dump(agent_spec_file_content, sort_keys=False, default_flow_style=False)
863
+ agent_spec_yaml_bytes = agent_spec_yaml.encode("utf-8")
864
+ agent_spec_yaml_file = io.BytesIO(agent_spec_yaml_bytes)
865
+
866
+ # Skip processing an agent if its already been saved
867
+ agent_file_path = f"{output_file_name}/agents/{agent_spec_file_content.get('kind', 'unknown')}/{agent_spec_file_content.get('name')}.yaml"
868
+ if check_file_in_zip(file_path=agent_file_path, zip_file=zip_file_out):
869
+ logger.warning(f"Skipping {agent_spec_file_content.get('name')}, agent with that name already exists in the output folder")
870
+ if close_file_flag:
871
+ zip_file_out.close()
872
+ return
873
+
874
+ zip_file_out.writestr(
875
+ agent_file_path,
876
+ agent_spec_yaml_file.getvalue()
877
+ )
878
+
879
+ tools_contoller = ToolsController()
880
+ for tool_name in agent_spec_file_content.get("tools", []):
881
+
882
+ base_tool_file_path = f"{output_file_name}/tools/{tool_name}/"
883
+ if check_file_in_zip(file_path=base_tool_file_path, zip_file=zip_file_out):
884
+ continue
885
+
886
+ logger.info(f"Exporting tool '{tool_name}'")
887
+ tool_artifact_bytes = tools_contoller.download_tool(tool_name)
888
+ if not tool_artifact_bytes:
889
+ continue
890
+
891
+ with zipfile.ZipFile(io.BytesIO(tool_artifact_bytes), "r") as zip_file_in:
892
+ for item in zip_file_in.infolist():
893
+ buffer = zip_file_in.read(item.filename)
894
+ if (item.filename != 'bundle-format'):
895
+ zip_file_out.writestr(
896
+ f"{base_tool_file_path}{item.filename}",
897
+ buffer
898
+ )
899
+
900
+ for kb_name in agent_spec_file_content.get("knowledge_base", []):
901
+ logger.warning(f"Skipping {kb_name}, knowledge_bases are currently unsupported by export")
902
+
903
+ if kind == AgentKind.NATIVE:
904
+ for collaborator_id in agent.collaborators:
905
+ collaborator = self.get_agent_by_id(collaborator_id)
906
+
907
+ if not collaborator:
908
+ logger.warning(f"Skipping {collaborator_id}, no agent with id {collaborator_id} found")
909
+ continue
910
+
911
+ self.export_agent(
912
+ name=collaborator.name,
913
+ kind=collaborator.kind,
914
+ output_path=output_path,
915
+ agent_only_flag=False,
916
+ zip_file_out=zip_file_out)
917
+
918
+ if close_file_flag:
919
+ logger.info(f"Successfully wrote agents and tools to '{output_path}'")
920
+ zip_file_out.close()
662
921