ibm-watsonx-orchestrate 1.12.0b1__py3-none-any.whl → 1.13.0b0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ibm_watsonx_orchestrate/__init__.py +2 -1
- ibm_watsonx_orchestrate/agent_builder/connections/types.py +34 -3
- ibm_watsonx_orchestrate/agent_builder/knowledge_bases/types.py +11 -2
- ibm_watsonx_orchestrate/agent_builder/models/types.py +17 -1
- ibm_watsonx_orchestrate/agent_builder/toolkits/types.py +14 -2
- ibm_watsonx_orchestrate/agent_builder/tools/__init__.py +1 -1
- ibm_watsonx_orchestrate/agent_builder/tools/langflow_tool.py +61 -1
- ibm_watsonx_orchestrate/agent_builder/tools/types.py +21 -3
- ibm_watsonx_orchestrate/agent_builder/voice_configurations/__init__.py +1 -1
- ibm_watsonx_orchestrate/agent_builder/voice_configurations/types.py +11 -0
- ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +27 -51
- ibm_watsonx_orchestrate/cli/commands/connections/connections_command.py +2 -2
- ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +54 -28
- ibm_watsonx_orchestrate/cli/commands/copilot/copilot_command.py +25 -2
- ibm_watsonx_orchestrate/cli/commands/copilot/copilot_controller.py +249 -14
- ibm_watsonx_orchestrate/cli/commands/copilot/copilot_server_controller.py +4 -4
- ibm_watsonx_orchestrate/cli/commands/environment/environment_command.py +5 -1
- ibm_watsonx_orchestrate/cli/commands/environment/environment_controller.py +6 -3
- ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_command.py +3 -2
- ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_controller.py +1 -1
- ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_controller.py +45 -16
- ibm_watsonx_orchestrate/cli/commands/models/models_command.py +2 -2
- ibm_watsonx_orchestrate/cli/commands/models/models_controller.py +29 -10
- ibm_watsonx_orchestrate/cli/commands/partners/offering/partners_offering_controller.py +21 -4
- ibm_watsonx_orchestrate/cli/commands/partners/offering/types.py +7 -15
- ibm_watsonx_orchestrate/cli/commands/server/server_command.py +19 -17
- ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_controller.py +139 -27
- ibm_watsonx_orchestrate/cli/commands/tools/tools_command.py +2 -2
- ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +79 -36
- ibm_watsonx_orchestrate/cli/commands/voice_configurations/voice_configurations_controller.py +23 -11
- ibm_watsonx_orchestrate/cli/common.py +26 -0
- ibm_watsonx_orchestrate/cli/config.py +33 -2
- ibm_watsonx_orchestrate/client/connections/connections_client.py +1 -14
- ibm_watsonx_orchestrate/client/copilot/cpe/copilot_cpe_client.py +34 -1
- ibm_watsonx_orchestrate/client/knowledge_bases/knowledge_base_client.py +6 -2
- ibm_watsonx_orchestrate/client/model_policies/model_policies_client.py +1 -1
- ibm_watsonx_orchestrate/client/models/models_client.py +1 -1
- ibm_watsonx_orchestrate/client/threads/threads_client.py +34 -0
- ibm_watsonx_orchestrate/client/utils.py +29 -7
- ibm_watsonx_orchestrate/docker/compose-lite.yml +2 -2
- ibm_watsonx_orchestrate/docker/default.env +15 -9
- ibm_watsonx_orchestrate/flow_builder/flows/decorators.py +2 -0
- ibm_watsonx_orchestrate/flow_builder/flows/flow.py +59 -9
- ibm_watsonx_orchestrate/flow_builder/node.py +13 -1
- ibm_watsonx_orchestrate/flow_builder/types.py +39 -0
- ibm_watsonx_orchestrate/langflow/__init__.py +0 -0
- ibm_watsonx_orchestrate/langflow/langflow_utils.py +195 -0
- ibm_watsonx_orchestrate/langflow/lfx_deps.py +84 -0
- ibm_watsonx_orchestrate/utils/async_helpers.py +31 -0
- ibm_watsonx_orchestrate/utils/docker_utils.py +1177 -33
- ibm_watsonx_orchestrate/utils/environment.py +165 -20
- ibm_watsonx_orchestrate/utils/exceptions.py +1 -1
- ibm_watsonx_orchestrate/utils/tokens.py +51 -0
- ibm_watsonx_orchestrate/utils/utils.py +63 -4
- {ibm_watsonx_orchestrate-1.12.0b1.dist-info → ibm_watsonx_orchestrate-1.13.0b0.dist-info}/METADATA +2 -2
- {ibm_watsonx_orchestrate-1.12.0b1.dist-info → ibm_watsonx_orchestrate-1.13.0b0.dist-info}/RECORD +59 -52
- {ibm_watsonx_orchestrate-1.12.0b1.dist-info → ibm_watsonx_orchestrate-1.13.0b0.dist-info}/WHEEL +0 -0
- {ibm_watsonx_orchestrate-1.12.0b1.dist-info → ibm_watsonx_orchestrate-1.13.0b0.dist-info}/entry_points.txt +0 -0
- {ibm_watsonx_orchestrate-1.12.0b1.dist-info → ibm_watsonx_orchestrate-1.13.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,4 @@
|
|
1
1
|
import logging
|
2
|
-
import asyncio
|
3
2
|
import importlib
|
4
3
|
import inspect
|
5
4
|
import sys
|
@@ -11,29 +10,28 @@ import zipfile
|
|
11
10
|
from enum import Enum
|
12
11
|
from os import path
|
13
12
|
from pathlib import Path
|
14
|
-
from typing import Iterable, List
|
13
|
+
from typing import Iterable, List, Any, Optional, cast
|
15
14
|
import rich
|
16
15
|
import json
|
17
|
-
from rich.json import JSON
|
18
16
|
import glob
|
19
17
|
|
20
18
|
import rich.table
|
21
19
|
import typer
|
22
20
|
|
23
|
-
from rich.console import Console
|
24
21
|
from rich.panel import Panel
|
25
22
|
|
26
|
-
from ibm_watsonx_orchestrate.agent_builder.tools import BaseTool, ToolSpec
|
23
|
+
from ibm_watsonx_orchestrate.agent_builder.tools import BaseTool, ToolSpec, ToolListEntry
|
27
24
|
from ibm_watsonx_orchestrate.agent_builder.tools.flow_tool import create_flow_json_tool
|
28
|
-
from ibm_watsonx_orchestrate.agent_builder.tools.langflow_tool import create_langflow_tool
|
25
|
+
from ibm_watsonx_orchestrate.agent_builder.tools.langflow_tool import LangflowTool, create_langflow_tool
|
29
26
|
from ibm_watsonx_orchestrate.agent_builder.tools.openapi_tool import create_openapi_json_tools_from_uri,create_openapi_json_tools_from_content
|
30
27
|
from ibm_watsonx_orchestrate.cli.commands.models.models_controller import ModelHighlighter
|
31
28
|
from ibm_watsonx_orchestrate.cli.commands.tools.types import RegistryType
|
32
29
|
from ibm_watsonx_orchestrate.cli.commands.connections.connections_controller import configure_connection, remove_connection, add_connection
|
30
|
+
from ibm_watsonx_orchestrate.cli.common import ListFormats, rich_table_to_markdown
|
33
31
|
from ibm_watsonx_orchestrate.agent_builder.connections.types import ConnectionType, ConnectionEnvironment, ConnectionPreference
|
34
32
|
from ibm_watsonx_orchestrate.cli.config import Config, CONTEXT_SECTION_HEADER, CONTEXT_ACTIVE_ENV_OPT, \
|
35
33
|
PYTHON_REGISTRY_HEADER, PYTHON_REGISTRY_TYPE_OPT, PYTHON_REGISTRY_TEST_PACKAGE_VERSION_OVERRIDE_OPT, \
|
36
|
-
DEFAULT_CONFIG_FILE_CONTENT
|
34
|
+
DEFAULT_CONFIG_FILE_CONTENT, PYTHON_REGISTRY_SKIP_VERSION_CHECK_OPT
|
37
35
|
from ibm_watsonx_orchestrate.agent_builder.connections import ConnectionSecurityScheme, ExpectedCredentials
|
38
36
|
from ibm_watsonx_orchestrate.flow_builder.flows.decorators import FlowWrapper
|
39
37
|
from ibm_watsonx_orchestrate.client.tools.tool_client import ToolClient
|
@@ -42,6 +40,7 @@ from ibm_watsonx_orchestrate.client.connections import get_connections_client, g
|
|
42
40
|
from ibm_watsonx_orchestrate.client.utils import instantiate_client, is_local_dev
|
43
41
|
from ibm_watsonx_orchestrate.flow_builder.utils import import_flow_support_tools
|
44
42
|
from ibm_watsonx_orchestrate.utils.utils import sanitize_app_id
|
43
|
+
from ibm_watsonx_orchestrate.utils.async_helpers import run_coroutine_sync
|
45
44
|
from ibm_watsonx_orchestrate.utils.exceptions import BadRequest
|
46
45
|
from ibm_watsonx_orchestrate.client.tools.tempus_client import TempusClient
|
47
46
|
|
@@ -56,6 +55,11 @@ DEFAULT_LANGFLOW_TOOL_REQUIREMENTS = [
|
|
56
55
|
"lfx==0.1.8"
|
57
56
|
]
|
58
57
|
|
58
|
+
DEFAULT_LANGFLOW_RUNNER_MODULES = [
|
59
|
+
"lfx",
|
60
|
+
"lfx-nightly"
|
61
|
+
]
|
62
|
+
|
59
63
|
class ToolKind(str, Enum):
|
60
64
|
openapi = "openapi"
|
61
65
|
python = "python"
|
@@ -615,7 +619,7 @@ def get_whl_in_registry(registry_url: str, version: str) -> str| None:
|
|
615
619
|
return wheel_file
|
616
620
|
|
617
621
|
class ToolsController:
|
618
|
-
def __init__(self, tool_kind: ToolKind = None, file: str = None, requirements_file: str = None):
|
622
|
+
def __init__(self, tool_kind: ToolKind = None, file: str = None, requirements_file: Optional[str] = None):
|
619
623
|
self.client = None
|
620
624
|
self.tool_kind = tool_kind
|
621
625
|
self.file = file
|
@@ -651,14 +655,14 @@ class ToolsController:
|
|
651
655
|
app_id = app_id[0]
|
652
656
|
connection = connections_client.get_draft_by_app_id(app_id=app_id)
|
653
657
|
connection_id = connection.connection_id
|
654
|
-
tools =
|
658
|
+
tools = run_coroutine_sync(import_openapi_tool(file=args["file"], connection_id=connection_id))
|
655
659
|
case "flow":
|
656
|
-
tools =
|
660
|
+
tools = run_coroutine_sync(import_flow_tool(file=args["file"]))
|
657
661
|
case "skill":
|
658
662
|
tools = []
|
659
663
|
logger.warning("Skill Import not implemented yet")
|
660
664
|
case "langflow":
|
661
|
-
tools =
|
665
|
+
tools = run_coroutine_sync(import_langflow_tool(file=args["file"],app_id=args.get('app_id',None)))
|
662
666
|
case _:
|
663
667
|
raise BadRequest("Invalid kind selected")
|
664
668
|
|
@@ -669,14 +673,18 @@ class ToolsController:
|
|
669
673
|
yield tool
|
670
674
|
|
671
675
|
|
672
|
-
def list_tools(self, verbose=False):
|
676
|
+
def list_tools(self, verbose=False, format: ListFormats| None = None) -> List[dict[str, Any]] | str | None:
|
677
|
+
if verbose and format:
|
678
|
+
logger.error("For tools list, `--verbose` and `--format` are mutually exclusive options")
|
679
|
+
sys.exit(1)
|
680
|
+
|
673
681
|
response = self.get_client().get()
|
674
682
|
tool_specs = []
|
675
683
|
parse_errors = []
|
676
684
|
|
677
685
|
for tool in response:
|
678
686
|
try:
|
679
|
-
tool_specs.append(ToolSpec.model_validate(tool))
|
687
|
+
tool_specs.append(ToolSpec.model_validate(tool, context="list"))
|
680
688
|
except Exception as e:
|
681
689
|
name = tool.get('name', None)
|
682
690
|
parse_errors.append([
|
@@ -693,12 +701,19 @@ class ToolsController:
|
|
693
701
|
tools_list.append(json.loads(tool.dumps_spec()))
|
694
702
|
|
695
703
|
rich.print_json(json.dumps(tools_list, indent=4))
|
704
|
+
return tools_list
|
696
705
|
else:
|
706
|
+
tool_details = []
|
707
|
+
|
708
|
+
connections_client = get_connections_client()
|
709
|
+
connections = connections_client.list()
|
710
|
+
|
711
|
+
connections_dict = {conn.connection_id: conn for conn in connections}
|
712
|
+
|
697
713
|
table = rich.table.Table(show_header=True, header_style="bold white", show_lines=True)
|
698
714
|
column_args = {
|
699
715
|
"Name": {"overflow": "fold"},
|
700
716
|
"Description": {},
|
701
|
-
"Permission": {},
|
702
717
|
"Type": {},
|
703
718
|
"Toolkit": {},
|
704
719
|
"App ID": {"overflow": "fold"}
|
@@ -706,11 +721,6 @@ class ToolsController:
|
|
706
721
|
for column in column_args:
|
707
722
|
table.add_column(column,**column_args[column])
|
708
723
|
|
709
|
-
connections_client = get_connections_client()
|
710
|
-
connections = connections_client.list()
|
711
|
-
|
712
|
-
connections_dict = {conn.connection_id: conn for conn in connections}
|
713
|
-
|
714
724
|
for tool in tools:
|
715
725
|
tool_binding = tool.__tool_spec__.binding
|
716
726
|
|
@@ -768,22 +778,31 @@ class ToolsController:
|
|
768
778
|
toolkit_name = toolkit["name"]
|
769
779
|
elif toolkit:
|
770
780
|
toolkit_name = str(toolkit)
|
771
|
-
|
772
781
|
|
773
|
-
|
774
|
-
tool.__tool_spec__.name,
|
775
|
-
tool.__tool_spec__.description,
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
", ".join(app_ids),
|
782
|
+
entry = ToolListEntry(
|
783
|
+
name=tool.__tool_spec__.name,
|
784
|
+
description=tool.__tool_spec__.description,
|
785
|
+
type=tool_type,
|
786
|
+
toolkit=toolkit_name,
|
787
|
+
app_ids=app_ids
|
780
788
|
)
|
781
789
|
|
782
|
-
|
790
|
+
if format == ListFormats.JSON:
|
791
|
+
tool_details.append(entry)
|
792
|
+
else:
|
793
|
+
table.add_row(*entry.get_row_details())
|
794
|
+
|
795
|
+
match format:
|
796
|
+
case ListFormats.JSON:
|
797
|
+
return tool_details
|
798
|
+
case ListFormats.Table:
|
799
|
+
return rich_table_to_markdown(table)
|
800
|
+
case _:
|
801
|
+
rich.print(table)
|
783
802
|
|
784
|
-
|
785
|
-
|
786
|
-
|
803
|
+
for error in parse_errors:
|
804
|
+
for l in error:
|
805
|
+
logger.error(l)
|
787
806
|
|
788
807
|
def get_all_tools(self) -> dict:
|
789
808
|
return {entry["name"]: entry["id"] for entry in self.get_client().get()}
|
@@ -851,15 +870,18 @@ class ToolsController:
|
|
851
870
|
|
852
871
|
cfg = Config()
|
853
872
|
registry_type = cfg.read(PYTHON_REGISTRY_HEADER, PYTHON_REGISTRY_TYPE_OPT) or DEFAULT_CONFIG_FILE_CONTENT[PYTHON_REGISTRY_HEADER][PYTHON_REGISTRY_TYPE_OPT]
|
873
|
+
skip_version_check = cfg.read(PYTHON_REGISTRY_HEADER, PYTHON_REGISTRY_SKIP_VERSION_CHECK_OPT) or DEFAULT_CONFIG_FILE_CONTENT[PYTHON_REGISTRY_HEADER][PYTHON_REGISTRY_SKIP_VERSION_CHECK_OPT]
|
854
874
|
|
855
875
|
version = __version__
|
856
876
|
if registry_type == RegistryType.LOCAL:
|
877
|
+
logger.warning(f"Using a local registry which is for development purposes only")
|
857
878
|
requirements.append(f"/packages/ibm_watsonx_orchestrate-0.6.0-py3-none-any.whl\n")
|
858
879
|
elif registry_type == RegistryType.PYPI:
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
880
|
+
if not skip_version_check:
|
881
|
+
wheel_file = get_whl_in_registry(registry_url='https://pypi.org/simple/ibm-watsonx-orchestrate', version=version)
|
882
|
+
if not wheel_file:
|
883
|
+
logger.error(f"Could not find ibm-watsonx-orchestrate@{version} on https://pypi.org/project/ibm-watsonx-orchestrate")
|
884
|
+
exit(1)
|
863
885
|
requirements.append(f"ibm-watsonx-orchestrate=={version}\n")
|
864
886
|
elif registry_type == RegistryType.TESTPYPI:
|
865
887
|
override_version = cfg.get(PYTHON_REGISTRY_HEADER, PYTHON_REGISTRY_TEST_PACKAGE_VERSION_OVERRIDE_OPT) or version
|
@@ -890,13 +912,34 @@ class ToolsController:
|
|
890
912
|
tool_path = Path(self.file)
|
891
913
|
zip_tool_artifacts.write(tool_path, arcname=f"{tool_path.stem}.json")
|
892
914
|
|
893
|
-
requirements =
|
915
|
+
requirements = []
|
894
916
|
|
895
917
|
if self.requirements_file:
|
896
918
|
requirements_file_path = Path(self.requirements_file)
|
897
919
|
requirements.extend(
|
898
920
|
get_requirement_lines(requirements_file=requirements_file_path, remove_trailing_newlines=False)
|
899
921
|
)
|
922
|
+
|
923
|
+
langflowTool = cast(LangflowTool, tool)
|
924
|
+
# if there are additional requriements from the langflow model, we should add it to the requirement set
|
925
|
+
if langflowTool.requirements and len(langflowTool.requirements) > 0:
|
926
|
+
requirements.extend(langflowTool.requirements)
|
927
|
+
|
928
|
+
# now check if the requirements contain modules listed in DEFAULT_LANGFLOW_RUNNER_MODULES
|
929
|
+
# if it is needed, we are assuming the user wants to override the default langflow module
|
930
|
+
# with a specific version
|
931
|
+
runner_overridden = False
|
932
|
+
for r in requirements:
|
933
|
+
# get the module name from the requirements
|
934
|
+
module_name = r.strip().split('==')[0].split('=')[0].split('>=')[0].split('<=')[0].split('~=')[0].lower()
|
935
|
+
if not module_name.startswith('#'):
|
936
|
+
if module_name in DEFAULT_LANGFLOW_RUNNER_MODULES:
|
937
|
+
runner_overridden = True
|
938
|
+
|
939
|
+
if not runner_overridden:
|
940
|
+
# add the default runner to the top of requirement list
|
941
|
+
requirements = DEFAULT_LANGFLOW_TOOL_REQUIREMENTS + list(requirements)
|
942
|
+
|
900
943
|
requirements_content = '\n'.join(requirements) + '\n'
|
901
944
|
zip_tool_artifacts.writestr("requirements.txt",requirements_content)
|
902
945
|
zip_tool_artifacts.writestr("bundle-format", "2.0.0\n")
|
ibm_watsonx_orchestrate/cli/commands/voice_configurations/voice_configurations_controller.py
CHANGED
@@ -3,10 +3,12 @@ import sys
|
|
3
3
|
import rich
|
4
4
|
import yaml
|
5
5
|
import logging
|
6
|
-
from
|
6
|
+
from typing import Optional, List, Any
|
7
|
+
from ibm_watsonx_orchestrate.agent_builder.voice_configurations import VoiceConfiguration, VoiceConfigurationListEntry
|
7
8
|
from ibm_watsonx_orchestrate.client.utils import instantiate_client
|
8
9
|
from ibm_watsonx_orchestrate.client.voice_configurations.voice_configurations_client import VoiceConfigurationsClient
|
9
10
|
from ibm_watsonx_orchestrate.utils.exceptions import BadRequest
|
11
|
+
from ibm_watsonx_orchestrate.cli.common import ListFormats, rich_table_to_markdown
|
10
12
|
|
11
13
|
logger = logging.getLogger(__name__)
|
12
14
|
|
@@ -69,12 +71,13 @@ class VoiceConfigurationsController:
|
|
69
71
|
|
70
72
|
return configs[0]
|
71
73
|
|
72
|
-
def list_voice_configs(self, verbose: bool) -> None:
|
74
|
+
def list_voice_configs(self, verbose: bool, format: Optional[ListFormats]=None) -> List[dict[str | Any]] | List[VoiceConfigurationListEntry] | str | None:
|
73
75
|
voice_configs = self.fetch_voice_configs()
|
74
76
|
|
75
77
|
if verbose:
|
76
78
|
json_configs = [json.loads(x.dumps_spec()) for x in voice_configs]
|
77
79
|
rich.print_json(json.dumps(json_configs, indent=4))
|
80
|
+
return json_configs
|
78
81
|
else:
|
79
82
|
config_table = rich.table.Table(
|
80
83
|
show_header=True,
|
@@ -94,18 +97,27 @@ class VoiceConfigurationsController:
|
|
94
97
|
for column in column_args:
|
95
98
|
config_table.add_column(column, **column_args[column])
|
96
99
|
|
100
|
+
config_details = []
|
101
|
+
|
97
102
|
for config in voice_configs:
|
98
|
-
attached_agents = [x.
|
99
|
-
|
100
|
-
config.name,
|
101
|
-
config.voice_configuration_id,
|
102
|
-
config.speech_to_text.provider,
|
103
|
-
config.text_to_speech.provider,
|
104
|
-
|
103
|
+
attached_agents = [x.name or x.id for x in config.attached_agents]
|
104
|
+
entry = VoiceConfigurationListEntry(
|
105
|
+
name=config.name,
|
106
|
+
id=config.voice_configuration_id,
|
107
|
+
speech_to_text_provider=config.speech_to_text.provider,
|
108
|
+
text_to_speech_provider=config.text_to_speech.provider,
|
109
|
+
attached_agents=attached_agents
|
105
110
|
)
|
111
|
+
config_details.append(entry)
|
112
|
+
config_table.add_row(*entry.get_row_details())
|
106
113
|
|
107
|
-
|
108
|
-
|
114
|
+
match format:
|
115
|
+
case ListFormats.JSON:
|
116
|
+
return config_details
|
117
|
+
case ListFormats.Table:
|
118
|
+
return rich_table_to_markdown(config_table)
|
119
|
+
case _:
|
120
|
+
rich.print(config_table)
|
109
121
|
|
110
122
|
def create_voice_config(self, voice_config: VoiceConfiguration) -> str | None:
|
111
123
|
client = self.get_voice_configurations_client()
|
@@ -0,0 +1,26 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
from rich.table import Table
|
3
|
+
|
4
|
+
class ListFormats(str, Enum):
|
5
|
+
Table = "table"
|
6
|
+
JSON = "json"
|
7
|
+
|
8
|
+
def __str__(self):
|
9
|
+
return self.value
|
10
|
+
|
11
|
+
def __repr__(self):
|
12
|
+
return repr(self.value)
|
13
|
+
|
14
|
+
def rich_table_to_markdown(table: Table) -> str:
|
15
|
+
headers = [column.header for column in table.columns]
|
16
|
+
cols = [[cell for cell in col.cells] for col in table.columns]
|
17
|
+
rows = list(map(list, zip(*cols)))
|
18
|
+
|
19
|
+
# Header row
|
20
|
+
md = "| " + " | ".join(headers) + " |\n"
|
21
|
+
# Separator row
|
22
|
+
md += "| " + " | ".join(["---"] * len(headers)) + " |\n"
|
23
|
+
# # Data rows
|
24
|
+
for row in rows:
|
25
|
+
md += "| " + " | ".join(row) + " |\n"
|
26
|
+
return md
|
@@ -22,6 +22,7 @@ AUTH_MCSP_TOKEN_OPT = "wxo_mcsp_token"
|
|
22
22
|
AUTH_MCSP_TOKEN_EXPIRY_OPT = "wxo_mcsp_token_expiry"
|
23
23
|
CONTEXT_ACTIVE_ENV_OPT = "active_environment"
|
24
24
|
PYTHON_REGISTRY_TYPE_OPT = "type"
|
25
|
+
PYTHON_REGISTRY_SKIP_VERSION_CHECK_OPT = "skip_version_check"
|
25
26
|
PYTHON_REGISTRY_TEST_PACKAGE_VERSION_OVERRIDE_OPT = "test_package_version_override"
|
26
27
|
ENV_WXO_URL_OPT = "wxo_url"
|
27
28
|
ENV_IAM_URL_OPT = "iam_url"
|
@@ -40,7 +41,8 @@ DEFAULT_CONFIG_FILE_CONTENT = {
|
|
40
41
|
CONTEXT_SECTION_HEADER: {CONTEXT_ACTIVE_ENV_OPT: None},
|
41
42
|
PYTHON_REGISTRY_HEADER: {
|
42
43
|
PYTHON_REGISTRY_TYPE_OPT: str(RegistryType.PYPI),
|
43
|
-
PYTHON_REGISTRY_TEST_PACKAGE_VERSION_OVERRIDE_OPT: None
|
44
|
+
PYTHON_REGISTRY_TEST_PACKAGE_VERSION_OVERRIDE_OPT: None,
|
45
|
+
PYTHON_REGISTRY_SKIP_VERSION_CHECK_OPT: False
|
44
46
|
},
|
45
47
|
ENVIRONMENTS_SECTION_HEADER: {
|
46
48
|
PROTECTED_ENV_NAME: {
|
@@ -85,7 +87,8 @@ def _check_if_auth_config_file(folder, file):
|
|
85
87
|
|
86
88
|
def clear_protected_env_credentials_token():
|
87
89
|
auth_cfg = Config(config_file_folder=AUTH_CONFIG_FILE_FOLDER, config_file=AUTH_CONFIG_FILE)
|
88
|
-
auth_cfg.
|
90
|
+
if auth_cfg.exists(AUTH_SECTION_HEADER, PROTECTED_ENV_NAME, AUTH_MCSP_TOKEN_OPT):
|
91
|
+
auth_cfg.delete(AUTH_SECTION_HEADER, PROTECTED_ENV_NAME, AUTH_MCSP_TOKEN_OPT)
|
89
92
|
|
90
93
|
|
91
94
|
class ConfigFileTypes(str, Enum):
|
@@ -230,3 +233,31 @@ class Config:
|
|
230
233
|
|
231
234
|
with open(self.config_file_path, 'w') as conf_file:
|
232
235
|
yaml.dump(deletion_data, conf_file, allow_unicode=True)
|
236
|
+
|
237
|
+
def exists(self, *args) -> bool:
|
238
|
+
"""
|
239
|
+
Determines if an item of arbitrary depth exists in the config file.
|
240
|
+
Takes an arbitrary number of args. Uses the args in order
|
241
|
+
as keys to access deeper sections of the config and then deleting the last specified key.
|
242
|
+
"""
|
243
|
+
if len(args) < 1:
|
244
|
+
raise BadRequest("Config.delete() requires at least one positional argument")
|
245
|
+
|
246
|
+
config_data = {}
|
247
|
+
try:
|
248
|
+
with open(self.config_file_path, 'r') as conf_file:
|
249
|
+
config_data = yaml_safe_load(conf_file) or {}
|
250
|
+
except FileNotFoundError:
|
251
|
+
pass
|
252
|
+
|
253
|
+
expression = "config_data"
|
254
|
+
for key in args:
|
255
|
+
temp = eval(expression)
|
256
|
+
|
257
|
+
if not isinstance(temp, dict) or key not in temp:
|
258
|
+
return False
|
259
|
+
|
260
|
+
else:
|
261
|
+
expression += f"['{key}']"
|
262
|
+
|
263
|
+
return True
|
@@ -3,27 +3,14 @@ from typing import List
|
|
3
3
|
from ibm_cloud_sdk_core.authenticators import MCSPAuthenticator
|
4
4
|
from pydantic import BaseModel, ValidationError
|
5
5
|
from typing import Optional
|
6
|
-
from enum import Enum
|
7
6
|
|
8
7
|
from ibm_watsonx_orchestrate.client.base_api_client import BaseAPIClient, ClientAPIException
|
9
|
-
from ibm_watsonx_orchestrate.agent_builder.connections.types import ConnectionEnvironment, ConnectionPreference, ConnectionConfiguration, ConnectionAuthType, ConnectionSecurityScheme, IdpConfigData, AppConfigData, ConnectionType
|
8
|
+
from ibm_watsonx_orchestrate.agent_builder.connections.types import ConnectionEnvironment, ConnectionPreference, ConnectionConfiguration, ConnectionAuthType, ConnectionSecurityScheme, IdpConfigData, AppConfigData, ConnectionType, FetchConfigAuthTypes
|
10
9
|
from ibm_watsonx_orchestrate.client.utils import is_cpd_env, is_local_dev
|
11
10
|
|
12
11
|
import logging
|
13
12
|
logger = logging.getLogger(__name__)
|
14
13
|
|
15
|
-
|
16
|
-
class FetchConfigAuthTypes(str, Enum):
|
17
|
-
BASIC_AUTH = ConnectionType.BASIC_AUTH.value
|
18
|
-
BEARER_TOKEN = ConnectionType.BEARER_TOKEN.value
|
19
|
-
API_KEY_AUTH = ConnectionType.API_KEY_AUTH.value
|
20
|
-
OAUTH2_AUTH_CODE = ConnectionType.OAUTH2_AUTH_CODE.value
|
21
|
-
OAUTH2_IMPLICIT = 'oauth2_implicit'
|
22
|
-
OAUTH2_PASSWORD = ConnectionType.OAUTH2_PASSWORD.value
|
23
|
-
OAUTH2_CLIENT_CREDS = ConnectionType.OAUTH2_CLIENT_CREDS.value
|
24
|
-
OAUTH_ON_BEHALF_OF_FLOW = ConnectionType.OAUTH_ON_BEHALF_OF_FLOW.value
|
25
|
-
KEY_VALUE = ConnectionType.KEY_VALUE.value
|
26
|
-
|
27
14
|
class ListConfigsResponse(BaseModel):
|
28
15
|
connection_id: str = None,
|
29
16
|
app_id: str = None
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Dict, Any
|
1
|
+
from typing import Dict, Any, List
|
2
2
|
from uuid import uuid4
|
3
3
|
|
4
4
|
from ibm_watsonx_orchestrate.client.base_api_client import BaseAPIClient
|
@@ -37,6 +37,39 @@ class CPEClient(BaseAPIClient):
|
|
37
37
|
if response:
|
38
38
|
return response[-1]
|
39
39
|
|
40
|
+
def refine_agent_with_chats(self, instruction: str, tools: Dict[str, Any], collaborators: Dict[str, Any], knowledge_bases: Dict[str, Any], trajectories_with_feedback: List[List[dict]], model: str | None = None) -> dict:
|
41
|
+
"""
|
42
|
+
Refines an agent's instruction using provided chat trajectories and optional model name.
|
43
|
+
This method sends a payload containing the agent's current instruction and a list of chat trajectories
|
44
|
+
to the Copilot Prompt Engine (CPE) for refinement.
|
45
|
+
Optionally, a target model name can be specified to use in the refinement process.
|
46
|
+
Parameters:
|
47
|
+
instruction (str): The current instruction or prompt associated with the agent.
|
48
|
+
tools (Dict[str, Any]) - a dictionary containing the selected tools
|
49
|
+
collaborators (Dict[str, Any]) - a dictionary containing the selected collaborators
|
50
|
+
knowledge_bases (Dict[str, Any]) - a dictionary containing the selected knowledge_bases
|
51
|
+
trajectories_with_feedback (List[List[dict]]): A list of chat trajectories, where each trajectory is a list
|
52
|
+
of message dictionaries that may include user feedback.
|
53
|
+
model (str | None): Optional. The name of the model to use for refinement.
|
54
|
+
Returns:
|
55
|
+
dict: The last response from the CPE containing the refined instruction.
|
56
|
+
"""
|
57
|
+
|
58
|
+
payload = {
|
59
|
+
"trajectories_with_feedback":trajectories_with_feedback,
|
60
|
+
"instruction":instruction,
|
61
|
+
"tools": tools,
|
62
|
+
"collaborators": collaborators,
|
63
|
+
"knowledge_bases": knowledge_bases
|
64
|
+
}
|
65
|
+
|
66
|
+
if model:
|
67
|
+
payload["target_model_name"] = model
|
68
|
+
|
69
|
+
response = self._post_nd_json("/wxo-cpe/refine-agent-with-trajectories", data=payload)
|
70
|
+
|
71
|
+
if response:
|
72
|
+
return response[-1]
|
40
73
|
|
41
74
|
def init_with_context(self, model: str | None = None, context_data: Dict[str, Any] = None) -> dict:
|
42
75
|
payload = {
|
@@ -30,8 +30,12 @@ class KnowledgeBaseClient(BaseAPIClient):
|
|
30
30
|
def get_by_id(self, knowledge_base_id: str) -> dict:
|
31
31
|
return self._get(f"{self.base_endpoint}/{knowledge_base_id}")
|
32
32
|
|
33
|
-
def get_by_names(self,
|
34
|
-
formatted_names = [f"names={x}" for x in
|
33
|
+
def get_by_names(self, names: List[str]) -> List[dict]:
|
34
|
+
formatted_names = [f"names={x}" for x in names]
|
35
|
+
return self._get(f"{self.base_endpoint}?{'&'.join(formatted_names)}")
|
36
|
+
|
37
|
+
def get_by_ids(self, ids: List[str]) -> List[dict]:
|
38
|
+
formatted_names = [f"ids={x}" for x in ids]
|
35
39
|
return self._get(f"{self.base_endpoint}?{'&'.join(formatted_names)}")
|
36
40
|
|
37
41
|
def status(self, knowledge_base_id: str) -> dict:
|
@@ -58,7 +58,7 @@ class ModelPoliciesClient(BaseAPIClient):
|
|
58
58
|
return []
|
59
59
|
raise e
|
60
60
|
|
61
|
-
def get_draft_by_name(self, policy_name: str) -> ModelPolicy:
|
61
|
+
def get_draft_by_name(self, policy_name: str) -> List[ModelPolicy]:
|
62
62
|
return self.get_drafts_by_names([policy_name])
|
63
63
|
|
64
64
|
|
@@ -60,7 +60,7 @@ class ModelsClient(BaseAPIClient):
|
|
60
60
|
return []
|
61
61
|
raise e
|
62
62
|
|
63
|
-
def get_draft_by_name(self, model_name: str) -> ListVirtualModel:
|
63
|
+
def get_draft_by_name(self, model_name: str) -> List[ListVirtualModel]:
|
64
64
|
return self.get_drafts_by_names([model_name])
|
65
65
|
|
66
66
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
from ibm_watsonx_orchestrate.client.base_api_client import BaseAPIClient
|
2
|
+
|
3
|
+
|
4
|
+
class ThreadsClient(BaseAPIClient):
|
5
|
+
"""
|
6
|
+
Client to handle read operations for Threads (chat history- trajectories) endpoints
|
7
|
+
"""
|
8
|
+
|
9
|
+
def __init__(self, *args, **kwargs):
|
10
|
+
super().__init__(*args, **kwargs)
|
11
|
+
self.base_endpoint = "/threads"
|
12
|
+
|
13
|
+
def get_all_threads(self, agent_id) -> dict:
|
14
|
+
return self._get(self.base_endpoint, params={"agent_id": agent_id})
|
15
|
+
|
16
|
+
def get_thread_messages(self, thread_id) -> dict:
|
17
|
+
return self._get(f"{self.base_endpoint}/{thread_id}/messages")
|
18
|
+
|
19
|
+
def get(self) -> dict:
|
20
|
+
return self._get(self.base_endpoint)
|
21
|
+
|
22
|
+
def get_threads_messages(self, thread_ids: list[str]):
|
23
|
+
"""
|
24
|
+
get the messages for a list of threads (chats) ids
|
25
|
+
:param thread_ids:
|
26
|
+
:param threads_client:
|
27
|
+
:return:
|
28
|
+
"""
|
29
|
+
all_thread_messages = []
|
30
|
+
for thread_id in thread_ids:
|
31
|
+
thread_messages = self.get_thread_messages(thread_id=thread_id)
|
32
|
+
all_thread_messages.append(thread_messages)
|
33
|
+
|
34
|
+
return all_thread_messages
|
@@ -175,23 +175,24 @@ def instantiate_client(client: type[T] , url: str | None=None) -> T:
|
|
175
175
|
raise FileNotFoundError(message)
|
176
176
|
|
177
177
|
|
178
|
+
def get_arm_architectures () -> list[str]:
|
179
|
+
# NOTE: intentionally omitting 32 bit arm architectures.
|
180
|
+
return ["aarch64", "arm64", "arm", "aarch64_be", "armv8b", "armv8l"]
|
181
|
+
|
182
|
+
|
178
183
|
def get_architecture () -> str:
|
179
184
|
arch = platform.machine().lower()
|
180
185
|
if arch in ("amd64", "x86_64"):
|
181
186
|
return "amd64"
|
182
|
-
|
183
|
-
|
184
|
-
return "386"
|
185
|
-
|
186
|
-
elif arch in ("aarch64", "arm64", "arm"):
|
187
|
-
return "arm"
|
187
|
+
elif arch in get_arm_architectures():
|
188
|
+
return arch
|
188
189
|
|
189
190
|
else:
|
190
191
|
raise Exception("Unsupported architecture %s" % arch)
|
191
192
|
|
192
193
|
|
193
194
|
def is_arm_architecture () -> bool:
|
194
|
-
return platform.machine().lower() in (
|
195
|
+
return platform.machine().lower() in get_arm_architectures()
|
195
196
|
|
196
197
|
|
197
198
|
def get_os_type () -> str:
|
@@ -201,3 +202,24 @@ def get_os_type () -> str:
|
|
201
202
|
|
202
203
|
else:
|
203
204
|
raise Exception("Unsupported operating system %s" % system)
|
205
|
+
|
206
|
+
def concat_bin_files(target_bin_file: str, source_files: list[str], read_chunk_size: int = None,
|
207
|
+
delete_source_files_post: bool = True) -> None:
|
208
|
+
if read_chunk_size is None:
|
209
|
+
# default read chunk size is 100 MB.
|
210
|
+
read_chunk_size = 100 * 1024 * 1024
|
211
|
+
|
212
|
+
with open(target_bin_file, "wb") as target:
|
213
|
+
for source_file in source_files:
|
214
|
+
with open(source_file, "rb") as source:
|
215
|
+
while True:
|
216
|
+
source_chunk = source.read(read_chunk_size)
|
217
|
+
|
218
|
+
if source_chunk:
|
219
|
+
target.write(source_chunk)
|
220
|
+
|
221
|
+
else:
|
222
|
+
break
|
223
|
+
|
224
|
+
if delete_source_files_post is True:
|
225
|
+
os.remove(source_file)
|
@@ -241,7 +241,7 @@ services:
|
|
241
241
|
- "wxo-server-minio"
|
242
242
|
|
243
243
|
wxo-milvus-etcd:
|
244
|
-
image: quay.io/coreos/etcd
|
244
|
+
image: ${ETCD_REGISTRY:-quay.io}/coreos/etcd:${ETCD_TAG:-v3.5.18}
|
245
245
|
environment:
|
246
246
|
- ETCD_AUTO_COMPACTION_MODE=revision
|
247
247
|
- ETCD_AUTO_COMPACTION_RETENTION=1000
|
@@ -580,7 +580,7 @@ services:
|
|
580
580
|
# IBM AGENT-OPS
|
581
581
|
########################
|
582
582
|
elasticsearch:
|
583
|
-
image: docker.elastic.co/elasticsearch/elasticsearch
|
583
|
+
image: ${ELASTICSEARCH_REGISTRY:-docker.elastic.co}/elasticsearch/elasticsearch:${ELASTICSEARCH_TAG:-8.19.0}
|
584
584
|
profiles: [ibm-telemetry]
|
585
585
|
environment:
|
586
586
|
- discovery.type=single-node
|