ibm-watsonx-orchestrate 1.1.0__tar.gz → 1.3.0__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.
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/PKG-INFO +3 -2
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/pyproject.toml +2 -1
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/__init__.py +1 -1
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/agents/types.py +4 -1
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/knowledge_bases/knowledge_base.py +16 -3
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/knowledge_bases/knowledge_base_requests.py +4 -20
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/knowledge_bases/types.py +4 -13
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/tools/openapi_tool.py +4 -12
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/tools/types.py +18 -5
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +2 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_command.py +2 -2
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_controller.py +63 -38
- ibm_watsonx_orchestrate-1.3.0/src/ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_command.py +71 -0
- ibm_watsonx_orchestrate-1.3.0/src/ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_controller.py +212 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +49 -21
- ibm_watsonx_orchestrate-1.3.0/src/ibm_watsonx_orchestrate/cli/init_helper.py +43 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/main.py +7 -3
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/connections/connections_client.py +13 -13
- ibm_watsonx_orchestrate-1.3.0/src/ibm_watsonx_orchestrate/client/toolkit/toolkit_client.py +81 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/docker/compose-lite.yml +1 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/docker/default.env +7 -7
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/.gitignore +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/LICENSE +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/agents/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/agents/agent.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/agents/assistant_agent.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/agents/external_agent.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/connections/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/connections/connections.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/connections/types.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/tools/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/tools/base_tool.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/tools/python_tool.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/utils/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/agent_builder/utils/pydantic_utils.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/agents/agents_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/channels/channels_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/channels/channels_controller.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/channels/types.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/channels/webchat/channels_webchat_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/channels/webchat/channels_webchat_controller.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/chat/chat_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/connections/connections_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/environment/environment_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/environment/environment_controller.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/environment/types.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/login/login_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/models/models_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/server/server_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/settings/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/settings/observability/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/settings/observability/langfuse/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/settings/observability/langfuse/langfuse_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/settings/observability/observability_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/settings/settings_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/tools/tools_command.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/commands/tools/types.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/cli/config.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/agents/agent_client.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/agents/assistant_agent_client.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/agents/external_agent_client.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/analytics/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/analytics/llm/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/analytics/llm/analytics_llm_client.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/base_api_client.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/base_service_instance.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/client.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/client_errors.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/connections/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/connections/utils.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/credentials.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/knowledge_bases/knowledge_base_client.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/local_service_instance.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/service_instance.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/tools/tool_client.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/client/utils.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/docker/sdk/ibm_watsonx_orchestrate-0.6.0-py3-none-any.whl +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/docker/sdk/ibm_watsonx_orchestrate-0.6.0.tar.gz +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/docker/start-up.sh +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/docker/tempus/common-config.yaml +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/run/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/run/connections.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/utils/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/utils/logging/__init__.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/utils/logging/logger.py +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/utils/logging/logging.yaml +0 -0
- {ibm_watsonx_orchestrate-1.1.0 → ibm_watsonx_orchestrate-1.3.0}/src/ibm_watsonx_orchestrate/utils/utils.py +0 -0
@@ -1,12 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ibm-watsonx-orchestrate
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3.0
|
4
4
|
Summary: IBM watsonx.orchestrate SDK
|
5
5
|
Author-email: IBM <support@ibm.com>
|
6
6
|
License: MIT License
|
7
7
|
License-File: LICENSE
|
8
8
|
Requires-Python: <3.14,>=3.11
|
9
9
|
Requires-Dist: certifi>=2024.8.30
|
10
|
+
Requires-Dist: click<8.2.0,>=8.0.0
|
10
11
|
Requires-Dist: docstring-parser<1.0,>=0.16
|
11
12
|
Requires-Dist: httpx<1.0.0,>=0.28.1
|
12
13
|
Requires-Dist: ibm-cloud-sdk-core>=3.22.0
|
@@ -19,7 +20,7 @@ Requires-Dist: pydantic<3.0.0,>=2.10.3
|
|
19
20
|
Requires-Dist: pyjwt<3.0.0,>=2.10.1
|
20
21
|
Requires-Dist: python-dotenv>=1.0.0
|
21
22
|
Requires-Dist: pyyaml<7.0.0,>=6.0.2
|
22
|
-
Requires-Dist: requests>=2.32.
|
23
|
+
Requires-Dist: requests>=2.32.0
|
23
24
|
Requires-Dist: rich<14.0.0,>=13.9.4
|
24
25
|
Requires-Dist: typer<1.0.0,>=0.15.1
|
25
26
|
Requires-Dist: urllib3>=2.2.3
|
@@ -17,6 +17,7 @@ requires-python = ">=3.11, <3.14"
|
|
17
17
|
classifiers = []
|
18
18
|
dependencies = [
|
19
19
|
"certifi>=2024.8.30",
|
20
|
+
"click>=8.0.0,<8.2.0",
|
20
21
|
"docstring-parser>=0.16,<1.0",
|
21
22
|
"httpx>=0.28.1,<1.0.0",
|
22
23
|
"ibm-cloud-sdk-core>=3.22.0",
|
@@ -29,7 +30,7 @@ dependencies = [
|
|
29
30
|
"pyjwt>=2.10.1,<3.0.0",
|
30
31
|
"python-dotenv>=1.0.0",
|
31
32
|
"pyyaml>=6.0.2,<7.0.0",
|
32
|
-
"requests>=2.32.
|
33
|
+
"requests>=2.32.0",
|
33
34
|
"rich>=13.9.4,<14.0.0",
|
34
35
|
"typer>=0.15.1,<1.0.0",
|
35
36
|
"urllib3>=2.2.3"
|
@@ -5,6 +5,7 @@ from typing import List, Optional, Dict
|
|
5
5
|
from pydantic import BaseModel, model_validator, ConfigDict
|
6
6
|
from ibm_watsonx_orchestrate.agent_builder.tools import BaseTool
|
7
7
|
from ibm_watsonx_orchestrate.agent_builder.knowledge_bases.types import KnowledgeBaseSpec
|
8
|
+
from ibm_watsonx_orchestrate.agent_builder.knowledge_bases.knowledge_base import KnowledgeBase
|
8
9
|
from pydantic import Field, AliasChoices
|
9
10
|
from typing import Annotated
|
10
11
|
|
@@ -85,6 +86,8 @@ class AgentSpec(BaseAgentSpec):
|
|
85
86
|
def __init__(self, *args, **kwargs):
|
86
87
|
if "tools" in kwargs and kwargs["tools"]:
|
87
88
|
kwargs["tools"] = [x.__tool_spec__.name if isinstance(x, BaseTool) else x for x in kwargs["tools"]]
|
89
|
+
if "knowledge_base" in kwargs and kwargs["knowledge_base"]:
|
90
|
+
kwargs["knowledge_base"] = [x.name if isinstance(x, KnowledgeBase) else x for x in kwargs["knowledge_base"]]
|
88
91
|
if "collaborators" in kwargs and kwargs["collaborators"]:
|
89
92
|
kwargs["collaborators"] = [x.name if isinstance(x, BaseAgentSpec) else x for x in kwargs["collaborators"]]
|
90
93
|
super().__init__(*args, **kwargs)
|
@@ -101,7 +104,7 @@ class AgentSpec(BaseAgentSpec):
|
|
101
104
|
|
102
105
|
def validate_agent_fields(values: dict) -> dict:
|
103
106
|
# Check for empty strings or whitespace
|
104
|
-
for field in ["id", "name", "kind", "description", "collaborators", "tools"]:
|
107
|
+
for field in ["id", "name", "kind", "description", "collaborators", "tools", "knowledge_base"]:
|
105
108
|
value = values.get(field)
|
106
109
|
if value and not str(value).strip():
|
107
110
|
raise ValueError(f"{field} cannot be empty or just whitespace")
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import json
|
2
2
|
from ibm_watsonx_orchestrate.utils.utils import yaml_safe_load
|
3
|
-
from .types import KnowledgeBaseSpec
|
4
|
-
|
3
|
+
from .types import KnowledgeBaseSpec, KnowledgeBaseKind
|
4
|
+
from pydantic import model_validator
|
5
5
|
|
6
6
|
class KnowledgeBase(KnowledgeBaseSpec):
|
7
7
|
|
@@ -24,4 +24,17 @@ class KnowledgeBase(KnowledgeBaseSpec):
|
|
24
24
|
return f"KnowledgeBase(id='{self.id}', name='{self.name}', description='{self.description}')"
|
25
25
|
|
26
26
|
def __str__(self):
|
27
|
-
return self.__repr__()
|
27
|
+
return self.__repr__()
|
28
|
+
|
29
|
+
# Not a model validator since we only want to validate this on import
|
30
|
+
def validate_documents_or_index_exists(self):
|
31
|
+
if self.documents and self.conversational_search_tool and self.conversational_search_tool.index_config or \
|
32
|
+
(not self.documents and (not self.conversational_search_tool or not self.conversational_search_tool.index_config)):
|
33
|
+
raise ValueError("Must provide either \"documents\" or \"conversational_search_tool.index_config\", but not both")
|
34
|
+
return self
|
35
|
+
|
36
|
+
@model_validator(mode="after")
|
37
|
+
def validate_kind(self):
|
38
|
+
if self.kind != KnowledgeBaseKind.KNOWLEDGE_BASE:
|
39
|
+
raise ValueError(f"The specified kind '{self.kind}' cannot be used to create a knowledge base")
|
40
|
+
return self
|
@@ -1,12 +1,12 @@
|
|
1
1
|
import json
|
2
2
|
from ibm_watsonx_orchestrate.utils.utils import yaml_safe_load
|
3
|
-
from .types import
|
3
|
+
from .types import KnowledgeBaseSpec, PatchKnowledgeBase, KnowledgeBaseKind
|
4
4
|
|
5
5
|
|
6
|
-
class KnowledgeBaseCreateRequest(
|
6
|
+
class KnowledgeBaseCreateRequest(KnowledgeBaseSpec):
|
7
7
|
|
8
8
|
@staticmethod
|
9
|
-
def from_spec(file: str) -> '
|
9
|
+
def from_spec(file: str) -> 'KnowledgeBaseSpec':
|
10
10
|
with open(file, 'r') as f:
|
11
11
|
if file.endswith('.yaml') or file.endswith('.yml'):
|
12
12
|
content = yaml_safe_load(f)
|
@@ -15,20 +15,10 @@ class KnowledgeBaseCreateRequest(CreateKnowledgeBase):
|
|
15
15
|
else:
|
16
16
|
raise ValueError('file must end in .json, .yaml, or .yml')
|
17
17
|
|
18
|
-
if (content.get('documents') and content.get("conversational_search_tool", {}).get("index_config")) or \
|
19
|
-
(not content.get('documents') and not content.get("conversational_search_tool", {}).get("index_config")):
|
20
|
-
raise ValueError("Must provide either \"documents\" or \"conversational_search_tool.index_config\", but not both")
|
21
|
-
|
22
18
|
if not content.get("spec_version"):
|
23
19
|
raise ValueError(f"Field 'spec_version' not provided. Please ensure provided spec conforms to a valid spec format")
|
24
20
|
|
25
|
-
|
26
|
-
raise ValueError(f"Field 'kind' not provided. Should be 'knowledge_base'")
|
27
|
-
|
28
|
-
if content.get("kind") != KnowledgeBaseKind.KNOWLEDGE_BASE:
|
29
|
-
raise ValueError(f"Field 'kind' should be 'knowledge_base', but is set to '{content.get('kind')}'")
|
30
|
-
|
31
|
-
knowledge_base = CreateKnowledgeBase.model_validate(content)
|
21
|
+
knowledge_base = KnowledgeBaseSpec.model_validate(content)
|
32
22
|
|
33
23
|
return knowledge_base
|
34
24
|
|
@@ -48,12 +38,6 @@ class KnowledgeBaseUpdateRequest(PatchKnowledgeBase):
|
|
48
38
|
if not content.get("spec_version"):
|
49
39
|
raise ValueError(f"Field 'spec_version' not provided. Please ensure provided spec conforms to a valid spec format")
|
50
40
|
|
51
|
-
if not content.get("kind"):
|
52
|
-
raise ValueError(f"Field 'kind' not provided. Should be 'knowledge_base'")
|
53
|
-
|
54
|
-
if content.get("kind") != KnowledgeBaseKind.KNOWLEDGE_BASE:
|
55
|
-
raise ValueError(f"Field 'kind' should be 'knowledge_base', but is set to '{content.get('kind')}'")
|
56
|
-
|
57
41
|
patch = PatchKnowledgeBase.model_validate(content)
|
58
42
|
|
59
43
|
return patch
|
@@ -206,16 +206,6 @@ class KnowledgeBaseBuiltInVectorIndexConfig(BaseModel):
|
|
206
206
|
chunk_overlap: Optional[int] = None
|
207
207
|
limit: Optional[int] = None
|
208
208
|
|
209
|
-
class CreateKnowledgeBase(BaseModel):
|
210
|
-
"""request payload schema"""
|
211
|
-
name: Optional[str] = None
|
212
|
-
description: Optional[str] = None
|
213
|
-
documents: list[str] = None
|
214
|
-
vector_index: Optional[KnowledgeBaseBuiltInVectorIndexConfig] = None
|
215
|
-
conversational_search_tool: Optional[ConversationalSearchConfig] = None
|
216
|
-
prioritize_built_in_index: Optional[bool] = None
|
217
|
-
|
218
|
-
|
219
209
|
class PatchKnowledgeBase(BaseModel):
|
220
210
|
"""request payload schema"""
|
221
211
|
description: Optional[str] = None
|
@@ -224,20 +214,21 @@ class PatchKnowledgeBase(BaseModel):
|
|
224
214
|
prioritize_built_in_index: Optional[bool] = None
|
225
215
|
representation: Optional[KnowledgeBaseRepresentation] = None
|
226
216
|
|
227
|
-
|
228
217
|
class KnowledgeBaseSpec(BaseModel):
|
229
218
|
"""Schema for a complete knowledge-base."""
|
230
219
|
spec_version: SpecVersion = None
|
231
220
|
kind: KnowledgeBaseKind = KnowledgeBaseKind.KNOWLEDGE_BASE
|
232
221
|
id: Optional[UUID] = None
|
233
222
|
tenant_id: Optional[str] = None
|
234
|
-
name:
|
223
|
+
name: str
|
235
224
|
description: Optional[str] = None
|
236
225
|
vector_index: Optional[KnowledgeBaseBuiltInVectorIndexConfig] = None
|
237
226
|
conversational_search_tool: Optional[ConversationalSearchConfig] | Optional[UUID] = None
|
238
227
|
prioritize_built_in_index: Optional[bool] = None
|
228
|
+
representation: Optional[KnowledgeBaseRepresentation] = None
|
239
229
|
vector_index_id: Optional[UUID] = None
|
240
230
|
created_by: Optional[str] = None
|
241
231
|
created_on: Optional[datetime] = None
|
242
232
|
updated_at: Optional[datetime] = None
|
243
|
-
|
233
|
+
# For import/update
|
234
|
+
documents: list[str] = None
|
@@ -115,17 +115,9 @@ def create_openapi_json_tool(
|
|
115
115
|
raise ValueError(
|
116
116
|
f"Path {http_path} did not have an http_method {http_method}. Available methods are {list(route.keys())}")
|
117
117
|
|
118
|
-
operation_id = (
|
119
|
-
|
120
|
-
|
121
|
-
'_',
|
122
|
-
re.sub(
|
123
|
-
r'[^a-zA-Z_]',
|
124
|
-
'_',
|
125
|
-
route_spec.get('operationId', None)
|
126
|
-
)
|
127
|
-
)
|
128
|
-
) if route_spec.get('operationId', None) is not None else None
|
118
|
+
operation_id = re.sub( r'(\W|_)+', '_', route_spec.get('operationId') ) \
|
119
|
+
if route_spec.get('operationId', None) else None
|
120
|
+
|
129
121
|
spec_name = name or operation_id
|
130
122
|
spec_permission = permission or _action_to_perm(route_spec.get('x-ibm-operation', {}).get('action'))
|
131
123
|
if spec_name is None:
|
@@ -142,7 +134,7 @@ def create_openapi_json_tool(
|
|
142
134
|
description=spec_description,
|
143
135
|
permission=spec_permission
|
144
136
|
)
|
145
|
-
|
137
|
+
|
146
138
|
spec.input_schema = input_schema or ToolRequestBody(
|
147
139
|
type='object',
|
148
140
|
properties={},
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from enum import Enum
|
2
|
-
from typing import List, Any, Dict, Literal, Optional
|
2
|
+
from typing import List, Any, Dict, Literal, Optional, Union
|
3
3
|
|
4
4
|
from pydantic import BaseModel, model_validator, ConfigDict, Field, AliasChoices
|
5
5
|
|
@@ -14,7 +14,7 @@ class ToolPermission(str, Enum):
|
|
14
14
|
class JsonSchemaObject(BaseModel):
|
15
15
|
model_config = ConfigDict(extra='allow')
|
16
16
|
|
17
|
-
type: Optional[Literal['object', 'string', 'number', 'integer', 'boolean', 'array', 'null']] = None
|
17
|
+
type: Optional[Union[Literal['object', 'string', 'number', 'integer', 'boolean', 'array', 'null'], List[Literal['object', 'string', 'number', 'integer', 'boolean', 'array', 'null']]]] = None
|
18
18
|
title: str | None = None
|
19
19
|
description: str | None = None
|
20
20
|
properties: Optional[Dict[str, 'JsonSchemaObject']] = None
|
@@ -34,13 +34,19 @@ class JsonSchemaObject(BaseModel):
|
|
34
34
|
aliasName: str | None = None
|
35
35
|
"Runtime feature where the sdk can provide the original name of a field before prefixing"
|
36
36
|
|
37
|
+
@model_validator(mode='after')
|
38
|
+
def normalize_type_field(self) -> 'JsonSchemaObject':
|
39
|
+
if isinstance(self.type, list):
|
40
|
+
self.type = self.type[0]
|
41
|
+
return self
|
42
|
+
|
37
43
|
|
38
44
|
class ToolRequestBody(BaseModel):
|
39
45
|
model_config = ConfigDict(extra='allow')
|
40
46
|
|
41
47
|
type: Literal['object']
|
42
48
|
properties: Dict[str, JsonSchemaObject]
|
43
|
-
required: List[str]
|
49
|
+
required: Optional[List[str]] = None
|
44
50
|
|
45
51
|
|
46
52
|
class ToolResponseBody(BaseModel):
|
@@ -52,7 +58,7 @@ class ToolResponseBody(BaseModel):
|
|
52
58
|
items: JsonSchemaObject = None
|
53
59
|
uniqueItems: bool = None
|
54
60
|
anyOf: List['JsonSchemaObject'] = None
|
55
|
-
required: List[str] = None
|
61
|
+
required: Optional[List[str]] = None
|
56
62
|
|
57
63
|
class OpenApiSecurityScheme(BaseModel):
|
58
64
|
type: Literal['apiKey', 'http', 'oauth2', 'openIdConnect']
|
@@ -128,6 +134,10 @@ class SkillToolBinding(BaseModel):
|
|
128
134
|
class ClientSideToolBinding(BaseModel):
|
129
135
|
pass
|
130
136
|
|
137
|
+
class McpToolBinding(BaseModel):
|
138
|
+
server_url: Optional[str] = None
|
139
|
+
source: str
|
140
|
+
connections: Dict[str, str]
|
131
141
|
|
132
142
|
class ToolBinding(BaseModel):
|
133
143
|
openapi: OpenApiToolBinding = None
|
@@ -135,6 +145,7 @@ class ToolBinding(BaseModel):
|
|
135
145
|
wxflows: WxFlowsToolBinding = None
|
136
146
|
skill: SkillToolBinding = None
|
137
147
|
client_side: ClientSideToolBinding = None
|
148
|
+
mcp: McpToolBinding = None
|
138
149
|
|
139
150
|
@model_validator(mode='after')
|
140
151
|
def validate_binding_type(self) -> 'ToolBinding':
|
@@ -143,7 +154,8 @@ class ToolBinding(BaseModel):
|
|
143
154
|
self.python is not None,
|
144
155
|
self.wxflows is not None,
|
145
156
|
self.skill is not None,
|
146
|
-
self.client_side is not None
|
157
|
+
self.client_side is not None,
|
158
|
+
self.mcp is not None
|
147
159
|
]
|
148
160
|
if sum(bindings) == 0:
|
149
161
|
raise ValueError("One binding must be set")
|
@@ -159,4 +171,5 @@ class ToolSpec(BaseModel):
|
|
159
171
|
input_schema: ToolRequestBody = None
|
160
172
|
output_schema: ToolResponseBody = None
|
161
173
|
binding: ToolBinding = None
|
174
|
+
toolkit_id: str | None = None
|
162
175
|
|
@@ -11,6 +11,7 @@ from copy import deepcopy
|
|
11
11
|
|
12
12
|
from typing import Iterable, List
|
13
13
|
from ibm_watsonx_orchestrate.cli.commands.tools.tools_controller import import_python_tool
|
14
|
+
from ibm_watsonx_orchestrate.cli.commands.knowledge_bases.knowledge_bases_controller import import_python_knowledge_base
|
14
15
|
|
15
16
|
from ibm_watsonx_orchestrate.agent_builder.agents import (
|
16
17
|
Agent,
|
@@ -33,6 +34,7 @@ logger = logging.getLogger(__name__)
|
|
33
34
|
def import_python_agent(file: str) -> List[Agent | ExternalAgent | AssistantAgent]:
|
34
35
|
# Import tools
|
35
36
|
import_python_tool(file)
|
37
|
+
import_python_knowledge_base(file)
|
36
38
|
|
37
39
|
file_path = Path(file)
|
38
40
|
file_directory = file_path.parent
|
@@ -9,7 +9,7 @@ knowledge_bases_app = typer.Typer(no_args_is_help=True)
|
|
9
9
|
def knowledge_base_import(
|
10
10
|
file: Annotated[
|
11
11
|
str,
|
12
|
-
typer.Option("--file", "-f", help="YAML file with knowledge base definition"),
|
12
|
+
typer.Option("--file", "-f", help="YAML, JSON or Python file with knowledge base definition(s)"),
|
13
13
|
],
|
14
14
|
app_id: Annotated[
|
15
15
|
str, typer.Option(
|
@@ -25,7 +25,7 @@ def knowledge_base_import(
|
|
25
25
|
def knowledge_base_patch(
|
26
26
|
file: Annotated[
|
27
27
|
str,
|
28
|
-
typer.Option("--file", "-f", help="YAML file with knowledge base definition"),
|
28
|
+
typer.Option("--file", "-f", help="YAML or JSON file with knowledge base definition"),
|
29
29
|
],
|
30
30
|
name: Annotated[
|
31
31
|
str,
|
@@ -3,17 +3,44 @@ import json
|
|
3
3
|
import rich
|
4
4
|
import requests
|
5
5
|
import logging
|
6
|
+
import importlib
|
7
|
+
import inspect
|
8
|
+
from pathlib import Path
|
9
|
+
from typing import List
|
6
10
|
|
7
|
-
from ibm_watsonx_orchestrate.agent_builder.knowledge_bases.knowledge_base_requests import
|
11
|
+
from ibm_watsonx_orchestrate.agent_builder.knowledge_bases.knowledge_base_requests import KnowledgeBaseUpdateRequest
|
8
12
|
from ibm_watsonx_orchestrate.agent_builder.knowledge_bases.knowledge_base import KnowledgeBase
|
9
13
|
from ibm_watsonx_orchestrate.client.knowledge_bases.knowledge_base_client import KnowledgeBaseClient
|
10
14
|
from ibm_watsonx_orchestrate.client.base_api_client import ClientAPIException
|
11
15
|
from ibm_watsonx_orchestrate.client.connections import get_connections_client
|
12
|
-
|
13
16
|
from ibm_watsonx_orchestrate.client.utils import instantiate_client
|
14
17
|
|
15
18
|
logger = logging.getLogger(__name__)
|
16
19
|
|
20
|
+
def import_python_knowledge_base(file: str) -> List[KnowledgeBase]:
|
21
|
+
file_path = Path(file)
|
22
|
+
file_directory = file_path.parent
|
23
|
+
file_name = file_path.stem
|
24
|
+
sys.path.append(str(file_directory))
|
25
|
+
module = importlib.import_module(file_name)
|
26
|
+
del sys.path[-1]
|
27
|
+
|
28
|
+
knowledge_bases = []
|
29
|
+
for _, obj in inspect.getmembers(module):
|
30
|
+
if isinstance(obj, KnowledgeBase):
|
31
|
+
knowledge_bases.append(obj)
|
32
|
+
return knowledge_bases
|
33
|
+
|
34
|
+
def parse_file(file: str) -> List[KnowledgeBase]:
|
35
|
+
if file.endswith('.yaml') or file.endswith('.yml') or file.endswith(".json"):
|
36
|
+
knowledge_base = KnowledgeBase.from_spec(file=file)
|
37
|
+
return [knowledge_base]
|
38
|
+
elif file.endswith('.py'):
|
39
|
+
knowledge_bases = import_python_knowledge_base(file)
|
40
|
+
return knowledge_bases
|
41
|
+
else:
|
42
|
+
raise ValueError("file must end in .json, .yaml, .yml or .py")
|
43
|
+
|
17
44
|
def to_column_name(col: str):
|
18
45
|
return " ".join([word.capitalize() if not word[0].isupper() else word for word in col.split("_")])
|
19
46
|
|
@@ -34,45 +61,43 @@ class KnowledgeBaseController:
|
|
34
61
|
|
35
62
|
def import_knowledge_base(self, file: str, app_id: str):
|
36
63
|
client = self.get_client()
|
37
|
-
create_request = KnowledgeBaseCreateRequest.from_spec(file=file)
|
38
64
|
|
39
|
-
|
40
|
-
|
41
|
-
|
65
|
+
knowledge_bases = parse_file(file=file)
|
66
|
+
for kb in knowledge_bases:
|
67
|
+
try:
|
68
|
+
kb.validate_documents_or_index_exists()
|
69
|
+
if kb.documents:
|
42
70
|
file_dir = "/".join(file.split("/")[:-1])
|
43
|
-
files = [('files', (get_file_name(file_path), open(file_path if file_path.startswith("/") else f"{file_dir}/{file_path}", 'rb'))) for file_path in
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
71
|
+
files = [('files', (get_file_name(file_path), open(file_path if file_path.startswith("/") else (file_path if not file_dir else f"{file_dir}/{file_path}"), 'rb'))) for file_path in kb.documents]
|
72
|
+
|
73
|
+
payload = kb.model_dump(exclude_none=True);
|
74
|
+
payload.pop('documents');
|
75
|
+
|
76
|
+
client.create_built_in(payload=payload, files=files)
|
77
|
+
else:
|
78
|
+
if len(kb.conversational_search_tool.index_config) != 1:
|
79
|
+
raise ValueError(f"Must provide exactly one conversational_search_tool.index_config. Provided {len(kb.conversational_search_tool.index_config)}.")
|
80
|
+
|
81
|
+
if app_id:
|
82
|
+
connections_client = get_connections_client()
|
83
|
+
connection_id = None
|
84
|
+
if app_id is not None:
|
85
|
+
connections = connections_client.get_draft_by_app_id(app_id=app_id)
|
86
|
+
if not connections:
|
87
|
+
logger.error(f"No connection exists with the app-id '{app_id}'")
|
88
|
+
exit(1)
|
89
|
+
|
90
|
+
connection_id = connections.connection_id
|
91
|
+
kb.conversational_search_tool.index_config[0].connection_id = connection_id
|
92
|
+
|
93
|
+
client.create(payload=kb.model_dump(exclude_none=True))
|
55
94
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
logger.error(f"No connection exists with the app-id '{app_id}'")
|
63
|
-
exit(1)
|
64
|
-
|
65
|
-
connection_id = connections.connection_id
|
66
|
-
create_request.conversational_search_tool.index_config[0].connection_id = connection_id
|
67
|
-
|
68
|
-
client.create(payload=create_request.model_dump(exclude_none=True))
|
69
|
-
|
70
|
-
logger.info(f"Successfully imported knowledge base '{create_request.name}'")
|
71
|
-
except ClientAPIException as e:
|
72
|
-
if "duplicate key value violates unique constraint" in e.response.text:
|
73
|
-
logger.error(f"A knowledge base with the name '{create_request.name}' already exists. Failed to import knowledge base")
|
74
|
-
else:
|
75
|
-
logger.error(f"Error importing knowledge base '{create_request.name}\n' {e.response.text}")
|
95
|
+
logger.info(f"Successfully imported knowledge base '{kb.name}'")
|
96
|
+
except ClientAPIException as e:
|
97
|
+
if "duplicate key value violates unique constraint" in e.response.text:
|
98
|
+
logger.error(f"A knowledge base with the name '{kb.name}' already exists. Failed to import knowledge base")
|
99
|
+
else:
|
100
|
+
logger.error(f"Error importing knowledge base '{kb.name}\n' {e.response.text}")
|
76
101
|
|
77
102
|
def get_id(
|
78
103
|
self, id: str, name: str
|
ibm_watsonx_orchestrate-1.3.0/src/ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_command.py
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
import typer
|
2
|
+
from typing import List
|
3
|
+
from typing_extensions import Annotated, Optional
|
4
|
+
from ibm_watsonx_orchestrate.cli.commands.toolkit.toolkit_controller import ToolkitController, ToolkitKind
|
5
|
+
|
6
|
+
toolkits_app = typer.Typer(no_args_is_help=True)
|
7
|
+
|
8
|
+
@toolkits_app.command(name="import")
|
9
|
+
def import_toolkit(
|
10
|
+
kind: Annotated[
|
11
|
+
ToolkitKind,
|
12
|
+
typer.Option("--kind", "-k", help="Kind of toolkit, currently only MCP is supported"),
|
13
|
+
],
|
14
|
+
name: Annotated[
|
15
|
+
str,
|
16
|
+
typer.Option("--name", "-n", help="Name of the toolkit"),
|
17
|
+
],
|
18
|
+
description: Annotated[
|
19
|
+
str,
|
20
|
+
typer.Option("--description", help="Description of the toolkit"),
|
21
|
+
],
|
22
|
+
package_root: Annotated[
|
23
|
+
str,
|
24
|
+
typer.Option("--package-root", "-p", help="Root directory of the MCP server package"),
|
25
|
+
],
|
26
|
+
command: Annotated[
|
27
|
+
str,
|
28
|
+
typer.Option(
|
29
|
+
"--command",
|
30
|
+
help="Command to start the MCP server. Can be a string (e.g. 'node dist/index.js --transport stdio') "
|
31
|
+
"or a JSON-style list of arguments (e.g. '[\"node\", \"dist/index.js\", \"--transport\", \"stdio\"]'). "
|
32
|
+
"The first argument will be used as the executable, the rest as its arguments."
|
33
|
+
),
|
34
|
+
],
|
35
|
+
tools: Annotated[
|
36
|
+
Optional[str],
|
37
|
+
typer.Option("--tools", "-t", help="Comma-separated list of tools to import. Or you can use `*` to use all tools"),
|
38
|
+
] = None,
|
39
|
+
app_id: Annotated[
|
40
|
+
List[str],
|
41
|
+
typer.Option(
|
42
|
+
"--app-id", "-a",
|
43
|
+
help='The app id of the connection to associate with this tool. A application connection represents the server authentication credentials needed to connect to this tool. Only type key_value is currently supported for MCP.'
|
44
|
+
)
|
45
|
+
] = None
|
46
|
+
):
|
47
|
+
if tools == "*":
|
48
|
+
tool_list = ["*"] # Wildcard to use all tools
|
49
|
+
elif tools:
|
50
|
+
tool_list = [tool.strip() for tool in tools.split(",")]
|
51
|
+
else:
|
52
|
+
tool_list = None
|
53
|
+
|
54
|
+
toolkit_controller = ToolkitController(
|
55
|
+
kind=kind,
|
56
|
+
name=name,
|
57
|
+
description=description,
|
58
|
+
package_root=package_root,
|
59
|
+
command=command,
|
60
|
+
)
|
61
|
+
toolkit_controller.import_toolkit(tools=tool_list, app_id=app_id)
|
62
|
+
|
63
|
+
@toolkits_app.command(name="remove")
|
64
|
+
def remove_toolkit(
|
65
|
+
name: Annotated[
|
66
|
+
str,
|
67
|
+
typer.Option("--name", "-n", help="Name of the toolkit you wish to remove"),
|
68
|
+
],
|
69
|
+
):
|
70
|
+
toolkit_controller = ToolkitController()
|
71
|
+
toolkit_controller.remove_toolkit(name=name)
|