ibm-watsonx-orchestrate 1.0.1__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ibm_watsonx_orchestrate/__init__.py +2 -1
- ibm_watsonx_orchestrate/agent_builder/tools/python_tool.py +7 -2
- ibm_watsonx_orchestrate/agent_builder/tools/types.py +18 -5
- ibm_watsonx_orchestrate/cli/commands/server/server_command.py +179 -52
- ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_command.py +71 -0
- ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_controller.py +212 -0
- ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +40 -17
- ibm_watsonx_orchestrate/cli/config.py +5 -1
- ibm_watsonx_orchestrate/cli/main.py +7 -5
- ibm_watsonx_orchestrate/client/toolkit/toolkit_client.py +81 -0
- ibm_watsonx_orchestrate/docker/compose-lite.yml +13 -10
- ibm_watsonx_orchestrate/docker/default.env +21 -18
- {ibm_watsonx_orchestrate-1.0.1.dist-info → ibm_watsonx_orchestrate-1.2.0.dist-info}/METADATA +1 -1
- {ibm_watsonx_orchestrate-1.0.1.dist-info → ibm_watsonx_orchestrate-1.2.0.dist-info}/RECORD +17 -14
- {ibm_watsonx_orchestrate-1.0.1.dist-info → ibm_watsonx_orchestrate-1.2.0.dist-info}/WHEEL +0 -0
- {ibm_watsonx_orchestrate-1.0.1.dist-info → ibm_watsonx_orchestrate-1.2.0.dist-info}/entry_points.txt +0 -0
- {ibm_watsonx_orchestrate-1.0.1.dist-info → ibm_watsonx_orchestrate-1.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -121,6 +121,7 @@ def tool(
|
|
121
121
|
_desc = description
|
122
122
|
if description is None and doc is not None:
|
123
123
|
_desc = doc.description
|
124
|
+
|
124
125
|
|
125
126
|
spec = ToolSpec(
|
126
127
|
name=name or fn.__name__,
|
@@ -150,7 +151,11 @@ def tool(
|
|
150
151
|
|
151
152
|
sig = inspect.signature(fn)
|
152
153
|
if not input_schema:
|
153
|
-
|
154
|
+
try:
|
155
|
+
input_schema_model: type[BaseModel] = create_schema_from_function(spec.name, fn, parse_docstring=True)
|
156
|
+
except:
|
157
|
+
logger.warning("Unable to properly parse parameter descriptions due to incorrectly formatted docstring. This may result in degraded agent performance. To fix this, please ensure the docstring conforms to Google's docstring format.")
|
158
|
+
input_schema_model: type[BaseModel] = create_schema_from_function(spec.name, fn, parse_docstring=False)
|
154
159
|
input_schema_json = input_schema_model.model_json_schema()
|
155
160
|
input_schema_json = dereference_refs(input_schema_json)
|
156
161
|
|
@@ -165,7 +170,7 @@ def tool(
|
|
165
170
|
)
|
166
171
|
else:
|
167
172
|
spec.input_schema = input_schema
|
168
|
-
|
173
|
+
|
169
174
|
_validate_input_schema(spec.input_schema)
|
170
175
|
|
171
176
|
if not output_schema:
|
@@ -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
|
|
@@ -1,30 +1,25 @@
|
|
1
|
+
import importlib.resources as resources
|
1
2
|
import logging
|
2
|
-
import
|
3
|
+
import os
|
4
|
+
import platform
|
3
5
|
import subprocess
|
6
|
+
import sys
|
4
7
|
import tempfile
|
5
|
-
from pathlib import Path
|
6
|
-
import requests
|
7
8
|
import time
|
8
|
-
import
|
9
|
-
import platform
|
10
|
-
|
9
|
+
from pathlib import Path
|
11
10
|
|
12
|
-
import typer
|
13
|
-
import importlib.resources as resources
|
14
11
|
import jwt
|
12
|
+
import requests
|
13
|
+
import typer
|
14
|
+
from dotenv import dotenv_values
|
15
15
|
|
16
|
-
from dotenv import dotenv_values, load_dotenv
|
17
|
-
|
18
|
-
from ibm_watsonx_orchestrate.client.agents.agent_client import AgentClient
|
19
|
-
from ibm_watsonx_orchestrate.client.analytics.llm.analytics_llm_client import AnalyticsLLMClient, AnalyticsLLMConfig, \
|
20
|
-
AnalyticsLLMUpsertToolIdentifier
|
21
16
|
from ibm_watsonx_orchestrate.client.utils import instantiate_client, check_token_validity, is_local_dev
|
22
|
-
|
23
|
-
from ibm_watsonx_orchestrate.cli.
|
17
|
+
from ibm_watsonx_orchestrate.cli.commands.environment.environment_controller import _login
|
18
|
+
from ibm_watsonx_orchestrate.cli.config import LICENSE_HEADER, \
|
19
|
+
ENV_ACCEPT_LICENSE
|
24
20
|
from ibm_watsonx_orchestrate.cli.config import PROTECTED_ENV_NAME, clear_protected_env_credentials_token, Config, \
|
25
|
-
AUTH_CONFIG_FILE_FOLDER, AUTH_CONFIG_FILE, AUTH_MCSP_TOKEN_OPT,
|
26
|
-
|
27
|
-
from dotenv import dotenv_values, load_dotenv
|
21
|
+
AUTH_CONFIG_FILE_FOLDER, AUTH_CONFIG_FILE, AUTH_MCSP_TOKEN_OPT, AUTH_SECTION_HEADER, USER_ENV_CACHE_HEADER
|
22
|
+
from ibm_watsonx_orchestrate.client.agents.agent_client import AgentClient
|
28
23
|
|
29
24
|
logger = logging.getLogger(__name__)
|
30
25
|
|
@@ -52,11 +47,11 @@ def ensure_docker_compose_installed() -> list:
|
|
52
47
|
typer.echo("Unable to find an installed docker-compose or docker compose")
|
53
48
|
sys.exit(1)
|
54
49
|
|
55
|
-
def docker_login(
|
50
|
+
def docker_login(api_key: str, registry_url: str, username:str = "iamapikey") -> None:
|
56
51
|
logger.info(f"Logging into Docker registry: {registry_url} ...")
|
57
52
|
result = subprocess.run(
|
58
|
-
["docker", "login", "-u",
|
59
|
-
input=
|
53
|
+
["docker", "login", "-u", username, "--password-stdin", registry_url],
|
54
|
+
input=api_key.encode("utf-8"),
|
60
55
|
capture_output=True,
|
61
56
|
)
|
62
57
|
if result.returncode != 0:
|
@@ -64,6 +59,24 @@ def docker_login(iam_api_key: str, registry_url: str) -> None:
|
|
64
59
|
sys.exit(1)
|
65
60
|
logger.info("Successfully logged in to Docker.")
|
66
61
|
|
62
|
+
def docker_login_by_dev_edition_source(env_dict: dict, source: str) -> None:
|
63
|
+
registry_url = env_dict["REGISTRY_URL"]
|
64
|
+
if source == "internal":
|
65
|
+
iam_api_key = env_dict.get("DOCKER_IAM_KEY")
|
66
|
+
if not iam_api_key:
|
67
|
+
raise ValueError("DOCKER_IAM_KEY is required in the environment file if WO_DEVELOPER_EDITION_SOURCE is set to 'internal'.")
|
68
|
+
docker_login(iam_api_key, registry_url, "iamapikey")
|
69
|
+
elif source == "myibm":
|
70
|
+
wo_entitlement_key = env_dict.get("WO_ENTITLEMENT_KEY")
|
71
|
+
if not wo_entitlement_key:
|
72
|
+
raise ValueError("WO_ENTITLEMENT_KEY is required in the environment file.")
|
73
|
+
docker_login(wo_entitlement_key, registry_url, "cp")
|
74
|
+
elif source == "orchestrate":
|
75
|
+
wo_auth_type = env_dict.get("WO_AUTH_TYPE")
|
76
|
+
if not wo_auth_type:
|
77
|
+
raise ValueError("WO_AUTH_TYPE is required in the environment file if WO_DEVELOPER_EDITION_SOURCE is set to 'orchestrate'.")
|
78
|
+
api_key, username = get_docker_cred_by_wo_auth_type(env_dict, wo_auth_type)
|
79
|
+
docker_login(api_key, registry_url, username)
|
67
80
|
|
68
81
|
def get_compose_file() -> Path:
|
69
82
|
with resources.as_file(
|
@@ -93,9 +106,51 @@ def merge_env(
|
|
93
106
|
user_env = dotenv_values(str(user_env_path))
|
94
107
|
merged.update(user_env)
|
95
108
|
|
96
|
-
|
97
109
|
return merged
|
98
110
|
|
111
|
+
def get_default_registry_env_vars_by_dev_edition_source(env_dict: dict, source: str) -> dict[str,str]:
|
112
|
+
component_registry_var_names = {key for key in env_dict if key.endswith("_REGISTRY")}
|
113
|
+
|
114
|
+
result = {}
|
115
|
+
if source == "internal":
|
116
|
+
result["REGISTRY_URL"] = "us.icr.io"
|
117
|
+
for name in component_registry_var_names:
|
118
|
+
result[name] = "us.icr.io/watson-orchestrate-private"
|
119
|
+
elif source == "myibm":
|
120
|
+
result["REGISTRY_URL"] = "cp.icr.io"
|
121
|
+
for name in component_registry_var_names:
|
122
|
+
result[name] = "cp.icr.io/cp/wxo-lite"
|
123
|
+
elif source == "orchestrate":
|
124
|
+
raise NotImplementedError("The 'orchestrate' source is not implemented yet.")
|
125
|
+
# TODO: confirm with Tej about the registry url for orchestrate source
|
126
|
+
return result
|
127
|
+
|
128
|
+
def get_dev_edition_source(env_dict: dict) -> str:
|
129
|
+
source = env_dict.get("WO_DEVELOPER_EDITION_SOURCE")
|
130
|
+
|
131
|
+
if source:
|
132
|
+
return source
|
133
|
+
if env_dict.get("WO_INSTANCE"):
|
134
|
+
return "orchestrate"
|
135
|
+
return "myibm"
|
136
|
+
|
137
|
+
def get_docker_cred_by_wo_auth_type(env_dict: dict, auth_type: str) -> tuple[str, str]:
|
138
|
+
if auth_type in {"mcsp", "ibm_iam"}:
|
139
|
+
wo_api_key = env_dict.get("WO_API_KEY")
|
140
|
+
if not wo_api_key:
|
141
|
+
raise ValueError("WO_API_KEY is required in the environment file if the WO_AUTH_TYPE is set to 'mcsp' or 'ibm_iam'.")
|
142
|
+
return wo_api_key, "wouser"
|
143
|
+
elif auth_type == "cpd":
|
144
|
+
wo_api_key = env_dict.get("WO_API_KEY")
|
145
|
+
wo_password = env_dict.get("WO_PASSWORD")
|
146
|
+
if not wo_api_key and not wo_password:
|
147
|
+
raise ValueError("WO_API_KEY or WO_PASSWORD is required in the environment file if the WO_AUTH_TYPE is set to 'cpd'.")
|
148
|
+
wo_username = env_dict.get("WO_USERNAME")
|
149
|
+
if not wo_username:
|
150
|
+
raise ValueError("WO_USERNAME is required in the environment file if the WO_AUTH_TYPE is set to 'cpd'.")
|
151
|
+
return wo_api_key or wo_password, wo_username # type: ignore[return-value]
|
152
|
+
else:
|
153
|
+
raise ValueError(f"Unknown value for WO_AUTH_TYPE: {auth_type}. Must be one of ['mcsp', 'ibm_iam', 'cpd'].")
|
99
154
|
|
100
155
|
def apply_llm_api_key_defaults(env_dict: dict) -> None:
|
101
156
|
llm_value = env_dict.get("WATSONX_APIKEY")
|
@@ -138,7 +193,30 @@ def refresh_local_credentials() -> None:
|
|
138
193
|
clear_protected_env_credentials_token()
|
139
194
|
_login(name=PROTECTED_ENV_NAME, apikey=None)
|
140
195
|
|
196
|
+
NON_SECRET_ENV_ITEMS = {
|
197
|
+
"WO_DEVELOPER_EDITION_SOURCE",
|
198
|
+
"WO_INSTANCE",
|
199
|
+
"USE_SAAS_ML_TOOLS_RUNTIME",
|
200
|
+
"WXO_MCSP_EXCHANGE_URL",
|
201
|
+
"OPENSOURCE_REGISTRY_PROXY"
|
202
|
+
}
|
203
|
+
def persist_user_env(env: dict, include_secrets: bool = False) -> None:
|
204
|
+
if include_secrets:
|
205
|
+
persistable_env = env
|
206
|
+
else:
|
207
|
+
persistable_env = {k:env[k] for k in NON_SECRET_ENV_ITEMS if k in env}
|
141
208
|
|
209
|
+
cfg = Config()
|
210
|
+
cfg.save(
|
211
|
+
{
|
212
|
+
USER_ENV_CACHE_HEADER: persistable_env
|
213
|
+
}
|
214
|
+
)
|
215
|
+
|
216
|
+
def get_persisted_user_env() -> dict | None:
|
217
|
+
cfg = Config()
|
218
|
+
user_env = cfg.get(USER_ENV_CACHE_HEADER) if cfg.get(USER_ENV_CACHE_HEADER) else None
|
219
|
+
return user_env
|
142
220
|
|
143
221
|
def run_compose_lite(final_env_file: Path, experimental_with_langfuse=False, with_flow_runtime=False) -> None:
|
144
222
|
compose_path = get_compose_file()
|
@@ -256,12 +334,20 @@ def run_compose_lite_ui(user_env_file: Path) -> bool:
|
|
256
334
|
compose_path = get_compose_file()
|
257
335
|
compose_command = ensure_docker_compose_installed()
|
258
336
|
ensure_docker_installed()
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
337
|
+
|
338
|
+
default_env = read_env_file(get_default_env_file())
|
339
|
+
user_env = read_env_file(user_env_file) if user_env_file else {}
|
340
|
+
if not user_env:
|
341
|
+
user_env = get_persisted_user_env()
|
342
|
+
|
343
|
+
dev_edition_source = get_dev_edition_source(user_env)
|
344
|
+
default_registry_vars = get_default_registry_env_vars_by_dev_edition_source(default_env, source=dev_edition_source)
|
345
|
+
|
346
|
+
merged_env_dict = {
|
347
|
+
**default_env,
|
348
|
+
**default_registry_vars,
|
349
|
+
**user_env,
|
350
|
+
}
|
265
351
|
|
266
352
|
_login(name=PROTECTED_ENV_NAME)
|
267
353
|
auth_cfg = Config(AUTH_CONFIG_FILE_FOLDER, AUTH_CONFIG_FILE)
|
@@ -271,21 +357,17 @@ def run_compose_lite_ui(user_env_file: Path) -> bool:
|
|
271
357
|
tenant_id = token.get('woTenantId', None)
|
272
358
|
merged_env_dict['REACT_APP_TENANT_ID'] = tenant_id
|
273
359
|
|
274
|
-
|
275
|
-
registry_url = merged_env_dict.get("REGISTRY_URL")
|
276
|
-
if not registry_url:
|
277
|
-
logger.error("Error: REGISTRY_URL is required in the environment file.")
|
278
|
-
sys.exit(1)
|
279
|
-
|
280
360
|
agent_client = instantiate_client(AgentClient)
|
281
361
|
agents = agent_client.get()
|
282
362
|
if not agents:
|
283
363
|
logger.error("No agents found for the current environment. Please create an agent before starting the chat.")
|
284
364
|
sys.exit(1)
|
285
365
|
|
286
|
-
|
287
|
-
|
288
|
-
|
366
|
+
try:
|
367
|
+
docker_login_by_dev_edition_source(merged_env_dict, dev_edition_source)
|
368
|
+
except ValueError as ignored:
|
369
|
+
# do nothing, as the docker login here is not mandatory
|
370
|
+
pass
|
289
371
|
|
290
372
|
#These are to removed warning and not used in UI component
|
291
373
|
if not 'WATSONX_SPACE_ID' in merged_env_dict:
|
@@ -436,6 +518,35 @@ def run_compose_lite_logs(final_env_file: Path, is_reset: bool = False) -> None:
|
|
436
518
|
)
|
437
519
|
sys.exit(1)
|
438
520
|
|
521
|
+
def confirm_accepts_license_agreement(accepts_by_argument: bool):
|
522
|
+
cfg = Config()
|
523
|
+
accepts_license = cfg.read(LICENSE_HEADER, ENV_ACCEPT_LICENSE)
|
524
|
+
if accepts_license != True:
|
525
|
+
logger.warning(('''
|
526
|
+
By running the following command your machine will install IBM watsonx Orchestrate Developer Edition, which is governed by the following IBM license agreement:
|
527
|
+
- * https://www.ibm.com/support/customer/csol/terms/?id=L-YRMZ-PB6MHM&lc=en
|
528
|
+
Additionally, the following prerequisite open source programs will be obtained from Docker Hub and will be installed on your machine. Each of the below programs are Separately Licensed Code, and are governed by the separate license agreements identified below, and not by the IBM license agreement:
|
529
|
+
* redis (7.2) - https://github.com/redis/redis/blob/7.2.7/COPYING
|
530
|
+
* minio - https://github.com/minio/minio/blob/master/LICENSE
|
531
|
+
* milvus-io - https://github.com/milvus-io/milvus/blob/master/LICENSE
|
532
|
+
* etcd - https://github.com/etcd-io/etcd/blob/main/LICENSE
|
533
|
+
* clickhouse-server - https://github.com/ClickHouse/ClickHouse/blob/master/LICENSE
|
534
|
+
* langfuse - https://github.com/langfuse/langfuse/blob/main/LICENSE
|
535
|
+
After installation, you are solely responsible for obtaining and installing updates and fixes, including security patches, for the above prerequisite open source programs. To update images the customer will run `orchestrate server reset && orchestrate server start -e .env`.
|
536
|
+
''').strip())
|
537
|
+
if not accepts_by_argument:
|
538
|
+
result = input('\nTo accept the terms and conditions of the IBM license agreement and the Separately Licensed Code licenses above please enter "I accept": ')
|
539
|
+
else:
|
540
|
+
result = None
|
541
|
+
if result == 'I accept' or accepts_by_argument:
|
542
|
+
cfg.write(LICENSE_HEADER, ENV_ACCEPT_LICENSE, True)
|
543
|
+
else:
|
544
|
+
logger.error('The terms and conditions were not accepted, exiting.')
|
545
|
+
exit(1)
|
546
|
+
|
547
|
+
|
548
|
+
|
549
|
+
|
439
550
|
@server_app.command(name="start")
|
440
551
|
def server_start(
|
441
552
|
user_env_file: str = typer.Option(
|
@@ -454,33 +565,46 @@ def server_start(
|
|
454
565
|
help='Option to start server with tempus-runtime.',
|
455
566
|
hidden=True
|
456
567
|
)
|
568
|
+
,
|
569
|
+
persist_env_secrets: bool = typer.Option(
|
570
|
+
False,
|
571
|
+
'--persist-env-secrets', '-p',
|
572
|
+
help='Option to store secret values from the provided env file in the config file (~/.config/orchestrate/config.yaml)',
|
573
|
+
hidden=True
|
574
|
+
),
|
575
|
+
accept_terms_and_conditions: bool = typer.Option(
|
576
|
+
False,
|
577
|
+
"--accept-terms-and-conditions",
|
578
|
+
help="By providing this flag you accept the terms and conditions outlined in the logs on server start."
|
579
|
+
),
|
457
580
|
):
|
581
|
+
confirm_accepts_license_agreement(accept_terms_and_conditions)
|
582
|
+
|
458
583
|
if user_env_file and not Path(user_env_file).exists():
|
459
584
|
logger.error(f"Error: The specified environment file '{user_env_file}' does not exist.")
|
460
585
|
sys.exit(1)
|
461
586
|
ensure_docker_installed()
|
462
587
|
|
463
|
-
|
588
|
+
default_env = read_env_file(get_default_env_file())
|
589
|
+
user_env = read_env_file(user_env_file) if user_env_file else {}
|
590
|
+
persist_user_env(user_env, include_secrets=persist_env_secrets)
|
591
|
+
dev_edition_source = get_dev_edition_source(user_env)
|
592
|
+
default_registry_vars = get_default_registry_env_vars_by_dev_edition_source(default_env, source=dev_edition_source)
|
464
593
|
|
465
|
-
merged_env_dict =
|
466
|
-
|
467
|
-
|
468
|
-
|
594
|
+
merged_env_dict = {
|
595
|
+
**default_env,
|
596
|
+
**default_registry_vars,
|
597
|
+
**user_env,
|
598
|
+
}
|
469
599
|
|
470
600
|
merged_env_dict['DBTAG'] = get_dbtag_from_architecture(merged_env_dict=merged_env_dict)
|
471
601
|
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
registry_url = merged_env_dict.get("REGISTRY_URL")
|
478
|
-
if not registry_url:
|
479
|
-
logger.error("Error: REGISTRY_URL is required in the environment file.")
|
602
|
+
try:
|
603
|
+
docker_login_by_dev_edition_source(merged_env_dict, dev_edition_source)
|
604
|
+
except ValueError as e:
|
605
|
+
logger.error(f"Error: {e}")
|
480
606
|
sys.exit(1)
|
481
607
|
|
482
|
-
docker_login(iam_api_key, registry_url)
|
483
|
-
|
484
608
|
apply_llm_api_key_defaults(merged_env_dict)
|
485
609
|
|
486
610
|
|
@@ -511,6 +635,9 @@ def server_start(
|
|
511
635
|
|
512
636
|
logger.info(f"You can run `orchestrate env activate local` to set your environment or `orchestrate chat start` to start the UI service and begin chatting.")
|
513
637
|
|
638
|
+
if experimental_with_langfuse:
|
639
|
+
logger.info(f"You can access the observability platform Langfuse at http://localhost:3010, username: orchestrate@ibm.com, password: orchestrate")
|
640
|
+
|
514
641
|
if with_flow_runtime:
|
515
642
|
logger.info(f"Starting with flow runtime")
|
516
643
|
|
@@ -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)
|
@@ -0,0 +1,212 @@
|
|
1
|
+
import os
|
2
|
+
import zipfile
|
3
|
+
import tempfile
|
4
|
+
from typing import List, Optional
|
5
|
+
from enum import Enum
|
6
|
+
import logging
|
7
|
+
import sys
|
8
|
+
import re
|
9
|
+
import requests
|
10
|
+
from ibm_watsonx_orchestrate.client.toolkit.toolkit_client import ToolKitClient
|
11
|
+
from ibm_watsonx_orchestrate.client.utils import instantiate_client
|
12
|
+
from ibm_watsonx_orchestrate.utils.utils import sanatize_app_id
|
13
|
+
from ibm_watsonx_orchestrate.client.connections import get_connections_client
|
14
|
+
import typer
|
15
|
+
import json
|
16
|
+
from rich.console import Console
|
17
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
18
|
+
from ibm_watsonx_orchestrate.client.utils import is_local_dev
|
19
|
+
|
20
|
+
logger = logging.getLogger(__name__)
|
21
|
+
|
22
|
+
class ToolkitKind(str, Enum):
|
23
|
+
MCP = "mcp"
|
24
|
+
|
25
|
+
def get_connection_id(app_id: str) -> str:
|
26
|
+
connections_client = get_connections_client()
|
27
|
+
existing_draft_configuration = connections_client.get_config(app_id=app_id, env='draft')
|
28
|
+
existing_live_configuration = connections_client.get_config(app_id=app_id, env='live')
|
29
|
+
|
30
|
+
for config in [existing_draft_configuration, existing_live_configuration]:
|
31
|
+
if config and config.security_scheme != 'key_value_creds':
|
32
|
+
logger.error("Only key_value credentials are currently supported")
|
33
|
+
exit(1)
|
34
|
+
connection_id = None
|
35
|
+
if app_id is not None:
|
36
|
+
connection = connections_client.get(app_id=app_id)
|
37
|
+
if not connection:
|
38
|
+
logger.error(f"No connection exists with the app-id '{app_id}'")
|
39
|
+
exit(1)
|
40
|
+
connection_id = connection.connection_id
|
41
|
+
return connection_id
|
42
|
+
|
43
|
+
def validate_params(kind: str):
|
44
|
+
if kind != ToolkitKind.MCP:
|
45
|
+
raise ValueError(f"Unsupported toolkit kind: {kind}")
|
46
|
+
|
47
|
+
|
48
|
+
class ToolkitController:
|
49
|
+
def __init__(
|
50
|
+
self,
|
51
|
+
kind: ToolkitKind = None,
|
52
|
+
name: str = None,
|
53
|
+
description: str = None,
|
54
|
+
package_root: str = None,
|
55
|
+
command: str = None,
|
56
|
+
):
|
57
|
+
self.kind = kind
|
58
|
+
self.name = name
|
59
|
+
self.description = description
|
60
|
+
self.package_root = package_root
|
61
|
+
self.command = command
|
62
|
+
self.client = None
|
63
|
+
|
64
|
+
def get_client(self) -> ToolKitClient:
|
65
|
+
if not self.client:
|
66
|
+
self.client = instantiate_client(ToolKitClient)
|
67
|
+
return self.client
|
68
|
+
|
69
|
+
def import_toolkit(self, tools: Optional[List[str]] = None, app_id: Optional[List[str]] = None):
|
70
|
+
if not is_local_dev():
|
71
|
+
logger.error("This functionality is only available for Local Environments")
|
72
|
+
sys.exit(1)
|
73
|
+
|
74
|
+
if app_id and isinstance(app_id, str):
|
75
|
+
app_id = [app_id]
|
76
|
+
elif not app_id:
|
77
|
+
app_id = []
|
78
|
+
|
79
|
+
validate_params(kind=self.kind)
|
80
|
+
|
81
|
+
remapped_connections = self._remap_connections(app_id)
|
82
|
+
|
83
|
+
client = self.get_client()
|
84
|
+
draft_toolkits = client.get_draft_by_name(toolkit_name=self.name)
|
85
|
+
if len(draft_toolkits) > 0:
|
86
|
+
logger.error(f"Existing toolkit found with name '{self.name}'. Failed to create toolkit.")
|
87
|
+
sys.exit(1)
|
88
|
+
|
89
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
90
|
+
# Handle zip file or directory
|
91
|
+
if self.package_root.endswith(".zip") and os.path.isfile(self.package_root):
|
92
|
+
zip_file_path = self.package_root
|
93
|
+
else:
|
94
|
+
zip_file_path = os.path.join(tmpdir, os.path.basename(f"{self.package_root.rstrip(os.sep)}.zip"))
|
95
|
+
with zipfile.ZipFile(zip_file_path, "w", zipfile.ZIP_DEFLATED) as mcp_zip_tool_artifacts:
|
96
|
+
self._populate_zip(self.package_root, mcp_zip_tool_artifacts)
|
97
|
+
|
98
|
+
try:
|
99
|
+
command_parts = json.loads(self.command)
|
100
|
+
if not isinstance(command_parts, list):
|
101
|
+
raise ValueError("JSON command must be a list of strings")
|
102
|
+
except (json.JSONDecodeError, ValueError):
|
103
|
+
command_parts = self.command.split()
|
104
|
+
|
105
|
+
command = command_parts[0]
|
106
|
+
args = command_parts[1:]
|
107
|
+
|
108
|
+
console = Console()
|
109
|
+
# List tools if not provided
|
110
|
+
if tools is None:
|
111
|
+
with Progress(
|
112
|
+
SpinnerColumn(spinner_name="dots"),
|
113
|
+
TextColumn("[progress.description]{task.description}"),
|
114
|
+
transient=True,
|
115
|
+
console=console,
|
116
|
+
) as progress:
|
117
|
+
progress.add_task(description="No tools specified, retrieving all tools from provided MCP server", total=None)
|
118
|
+
tools = self.get_client().list_tools(
|
119
|
+
zip_file_path=zip_file_path,
|
120
|
+
command=command,
|
121
|
+
args=args,
|
122
|
+
)
|
123
|
+
# Normalize tools to a list of tool names
|
124
|
+
tools = [
|
125
|
+
tool["name"] if isinstance(tool, dict) and "name" in tool else tool
|
126
|
+
for tool in tools
|
127
|
+
]
|
128
|
+
|
129
|
+
|
130
|
+
logger.info("✅ The following tools will be imported:")
|
131
|
+
for tool in tools:
|
132
|
+
console.print(f" • {tool}")
|
133
|
+
|
134
|
+
|
135
|
+
# Create toolkit metadata
|
136
|
+
payload = {
|
137
|
+
"name": self.name,
|
138
|
+
"description": self.description,
|
139
|
+
"mcp": {
|
140
|
+
"source": "files",
|
141
|
+
"command": command,
|
142
|
+
"args": args,
|
143
|
+
"tools": tools,
|
144
|
+
"connections": remapped_connections,
|
145
|
+
}
|
146
|
+
}
|
147
|
+
toolkit = self.get_client().create_toolkit(payload)
|
148
|
+
toolkit_id = toolkit["id"]
|
149
|
+
|
150
|
+
console = Console()
|
151
|
+
# Upload zip file
|
152
|
+
with Progress(
|
153
|
+
SpinnerColumn(spinner_name="dots"),
|
154
|
+
TextColumn("[progress.description]{task.description}"),
|
155
|
+
transient=True,
|
156
|
+
console=console,
|
157
|
+
) as progress:
|
158
|
+
progress.add_task(description="Uploading toolkit zip file...", total=None)
|
159
|
+
self.get_client().upload(toolkit_id=toolkit_id, zip_file_path=zip_file_path)
|
160
|
+
logger.info(f"Successfully imported tool kit {self.name}")
|
161
|
+
|
162
|
+
def _populate_zip(self, package_root: str, zipfile: zipfile.ZipFile) -> str:
|
163
|
+
for root, _, files in os.walk(package_root):
|
164
|
+
for file in files:
|
165
|
+
full_path = os.path.join(root, file)
|
166
|
+
relative_path = os.path.relpath(full_path, start=package_root)
|
167
|
+
zipfile.write(full_path, arcname=relative_path)
|
168
|
+
return zipfile
|
169
|
+
|
170
|
+
def _remap_connections(self, app_ids: List[str]):
|
171
|
+
app_id_dict = {}
|
172
|
+
for app_id in app_ids:
|
173
|
+
split_pattern = re.compile(r"(?<!\\)=")
|
174
|
+
split_id = re.split(split_pattern, app_id)
|
175
|
+
split_id = [x.replace("\\=", "=") for x in split_id]
|
176
|
+
if len(split_id) == 2:
|
177
|
+
runtime_id, local_id = split_id
|
178
|
+
elif len(split_id) == 1:
|
179
|
+
runtime_id = split_id[0]
|
180
|
+
local_id = split_id[0]
|
181
|
+
else:
|
182
|
+
raise typer.BadParameter(f"The provided --app-id '{app_id}' is not valid. This is likely caused by having mutliple equal signs, please use '\\=' to represent a literal '=' character")
|
183
|
+
|
184
|
+
if not len(runtime_id.strip()) or not len(local_id.strip()):
|
185
|
+
raise typer.BadParameter(f"The provided --app-id '{app_id}' is not valid. --app-id cannot be empty or whitespace")
|
186
|
+
|
187
|
+
runtime_id = sanatize_app_id(runtime_id)
|
188
|
+
app_id_dict[runtime_id] = get_connection_id(local_id)
|
189
|
+
|
190
|
+
return app_id_dict
|
191
|
+
|
192
|
+
|
193
|
+
def remove_toolkit(self, name: str):
|
194
|
+
if not is_local_dev():
|
195
|
+
logger.error("This functionality is only available for Local Environments")
|
196
|
+
sys.exit(1)
|
197
|
+
try:
|
198
|
+
client = self.get_client()
|
199
|
+
draft_toolkits = client.get_draft_by_name(toolkit_name=name)
|
200
|
+
if len(draft_toolkits) > 1:
|
201
|
+
logger.error(f"Multiple existing toolkits found with name '{name}'. Failed to remove toolkit")
|
202
|
+
sys.exit(1)
|
203
|
+
if len(draft_toolkits) > 0:
|
204
|
+
draft_toolkit = draft_toolkits[0]
|
205
|
+
toolkit_id = draft_toolkit.get("id")
|
206
|
+
self.get_client().delete(toolkit_id=toolkit_id)
|
207
|
+
logger.info(f"Successfully removed tool {name}")
|
208
|
+
else:
|
209
|
+
logger.warning(f"No toolkit named '{name}' found")
|
210
|
+
except requests.HTTPError as e:
|
211
|
+
logger.error(e.response.text)
|
212
|
+
exit(1)
|
@@ -27,8 +27,9 @@ from ibm_watsonx_orchestrate.cli.config import Config, CONTEXT_SECTION_HEADER, C
|
|
27
27
|
DEFAULT_CONFIG_FILE_CONTENT
|
28
28
|
from ibm_watsonx_orchestrate.agent_builder.connections import ConnectionSecurityScheme, ExpectedCredentials
|
29
29
|
from ibm_watsonx_orchestrate.client.tools.tool_client import ToolClient
|
30
|
+
from ibm_watsonx_orchestrate.client.toolkit.toolkit_client import ToolKitClient
|
30
31
|
from ibm_watsonx_orchestrate.client.connections import get_connections_client, get_connection_type
|
31
|
-
from ibm_watsonx_orchestrate.client.utils import instantiate_client
|
32
|
+
from ibm_watsonx_orchestrate.client.utils import instantiate_client, is_local_dev
|
32
33
|
from ibm_watsonx_orchestrate.utils.utils import sanatize_app_id
|
33
34
|
|
34
35
|
from ibm_watsonx_orchestrate import __version__
|
@@ -41,6 +42,7 @@ __supported_characters_pattern = re.compile("^(\\w|_)+$")
|
|
41
42
|
class ToolKind(str, Enum):
|
42
43
|
openapi = "openapi"
|
43
44
|
python = "python"
|
45
|
+
mcp = "mcp"
|
44
46
|
# skill = "skill"
|
45
47
|
|
46
48
|
def validate_app_ids(kind: ToolKind, **args) -> None:
|
@@ -275,14 +277,8 @@ def import_python_tool(file: str, requirements_file: str = None, app_id: List[st
|
|
275
277
|
resolved_requirements_file = get_resolved_py_tool_reqs_file(tool_file=file, requirements_file=requirements_file,
|
276
278
|
package_root=resolved_package_root)
|
277
279
|
|
278
|
-
if resolved_requirements_file is None:
|
279
|
-
logger.
|
280
|
-
|
281
|
-
if resolved_requirements_file != requirements_file:
|
282
|
-
logger.info(f"Resolved Requirements file: \"{resolved_requirements_file}\"")
|
283
|
-
|
284
|
-
else:
|
285
|
-
logger.info(f"Requirements file: \"{requirements_file}\"")
|
280
|
+
if resolved_requirements_file is not None:
|
281
|
+
logger.info(f"Using requirement file: \"{resolved_requirements_file}\"")
|
286
282
|
|
287
283
|
if resolved_requirements_file is not None:
|
288
284
|
try:
|
@@ -374,21 +370,24 @@ class ToolsController:
|
|
374
370
|
response = self.get_client().get()
|
375
371
|
tool_specs = [ToolSpec.model_validate(tool) for tool in response]
|
376
372
|
tools = [BaseTool(spec=spec) for spec in tool_specs]
|
377
|
-
|
378
373
|
|
379
374
|
if verbose:
|
380
375
|
tools_list = []
|
381
376
|
for tool in tools:
|
382
|
-
|
383
377
|
tools_list.append(json.loads(tool.dumps_spec()))
|
384
378
|
|
385
379
|
rich.print(JSON(json.dumps(tools_list, indent=4)))
|
386
380
|
else:
|
387
381
|
table = rich.table.Table(show_header=True, header_style="bold white", show_lines=True)
|
388
|
-
columns = ["Name", "Description", "Permission", "Type", "App ID"]
|
382
|
+
columns = ["Name", "Description", "Permission", "Type", "Toolkit", "App ID"]
|
389
383
|
for column in columns:
|
390
384
|
table.add_column(column)
|
391
|
-
|
385
|
+
|
386
|
+
connections_client = get_connections_client()
|
387
|
+
connections = connections_client.list()
|
388
|
+
|
389
|
+
connections_dict = {conn.connection_id: conn for conn in connections}
|
390
|
+
|
392
391
|
for tool in tools:
|
393
392
|
tool_binding = tool.__tool_spec__.binding
|
394
393
|
|
@@ -400,25 +399,49 @@ class ToolsController:
|
|
400
399
|
elif tool_binding.python is not None and hasattr(tool_binding.python, "connections") and tool_binding.python.connections is not None:
|
401
400
|
for conn in tool_binding.python.connections:
|
402
401
|
connection_ids.append(tool_binding.python.connections[conn])
|
403
|
-
|
404
|
-
|
402
|
+
elif tool_binding.mcp is not None and hasattr(tool_binding.mcp, "connections"):
|
403
|
+
for conn in tool_binding.mcp.connections:
|
404
|
+
connection_ids.append(tool_binding.mcp.connections[conn])
|
405
|
+
|
406
|
+
|
405
407
|
app_ids = []
|
406
408
|
for connection_id in connection_ids:
|
407
|
-
|
409
|
+
connection = connections_dict.get(connection_id)
|
410
|
+
if connection:
|
411
|
+
app_id = str(connection.app_id or connection.connection_id)
|
412
|
+
elif connection_id:
|
413
|
+
app_id = str(connection_id)
|
414
|
+
else:
|
415
|
+
app_id = ""
|
408
416
|
app_ids.append(app_id)
|
409
417
|
|
410
418
|
if tool_binding.python is not None:
|
411
419
|
tool_type=ToolKind.python
|
412
420
|
elif tool_binding.openapi is not None:
|
413
421
|
tool_type=ToolKind.openapi
|
422
|
+
elif tool_binding.mcp is not None:
|
423
|
+
tool_type=ToolKind.mcp
|
414
424
|
else:
|
415
425
|
tool_type="Unknown"
|
416
426
|
|
427
|
+
toolkit_name = ""
|
428
|
+
|
429
|
+
if is_local_dev():
|
430
|
+
toolkit_client = instantiate_client(ToolKitClient)
|
431
|
+
if tool.__tool_spec__.toolkit_id:
|
432
|
+
toolkit = toolkit_client.get_draft_by_id(tool.__tool_spec__.toolkit_id)
|
433
|
+
if isinstance(toolkit, dict) and "name" in toolkit:
|
434
|
+
toolkit_name = toolkit["name"]
|
435
|
+
elif toolkit:
|
436
|
+
toolkit_name = str(toolkit)
|
437
|
+
|
438
|
+
|
417
439
|
table.add_row(
|
418
440
|
tool.__tool_spec__.name,
|
419
441
|
tool.__tool_spec__.description,
|
420
442
|
tool.__tool_spec__.permission,
|
421
443
|
tool_type,
|
444
|
+
toolkit_name,
|
422
445
|
", ".join(app_ids),
|
423
446
|
)
|
424
447
|
|
@@ -472,7 +495,7 @@ class ToolsController:
|
|
472
495
|
raise typer.BadParameter(f"Symbolic links in packages are not supported. - {path_str}")
|
473
496
|
|
474
497
|
try:
|
475
|
-
zip_tool_artifacts.write(path_str, arcname=
|
498
|
+
zip_tool_artifacts.write(path_str, arcname=str(Path(path_str).relative_to(Path(resolved_package_root))))
|
476
499
|
|
477
500
|
except Exception as ex:
|
478
501
|
logger.error(f"Could not write file {path_str} to artifact. {ex}")
|
@@ -12,6 +12,8 @@ AUTH_SECTION_HEADER = "auth"
|
|
12
12
|
CONTEXT_SECTION_HEADER = "context"
|
13
13
|
ENVIRONMENTS_SECTION_HEADER = "environments"
|
14
14
|
PYTHON_REGISTRY_HEADER = "python_registry"
|
15
|
+
USER_ENV_CACHE_HEADER = "cached_user_env"
|
16
|
+
LICENSE_HEADER = "license"
|
15
17
|
|
16
18
|
# Option Names
|
17
19
|
AUTH_MCSP_API_KEY_OPT = "wxo_mcsp_api_key"
|
@@ -24,6 +26,7 @@ ENV_WXO_URL_OPT = "wxo_url"
|
|
24
26
|
ENV_IAM_URL_OPT = "iam_url"
|
25
27
|
PROTECTED_ENV_NAME = "local"
|
26
28
|
ENV_AUTH_TYPE = "auth_type"
|
29
|
+
ENV_ACCEPT_LICENSE = 'accepts_license_agreements'
|
27
30
|
|
28
31
|
DEFAULT_LOCAL_SERVICE_URL = "http://localhost:4321"
|
29
32
|
CHAT_UI_PORT = "3000"
|
@@ -40,7 +43,8 @@ DEFAULT_CONFIG_FILE_CONTENT = {
|
|
40
43
|
PROTECTED_ENV_NAME: {
|
41
44
|
ENV_WXO_URL_OPT: DEFAULT_LOCAL_SERVICE_URL
|
42
45
|
}
|
43
|
-
}
|
46
|
+
},
|
47
|
+
USER_ENV_CACHE_HEADER: {}
|
44
48
|
}
|
45
49
|
|
46
50
|
AUTH_CONFIG_FILE_FOLDER = f"{os.path.expanduser('~')}/.cache/orchestrate"
|
@@ -11,6 +11,7 @@ from ibm_watsonx_orchestrate.cli.commands.models.models_command import models_ap
|
|
11
11
|
from ibm_watsonx_orchestrate.cli.commands.environment.environment_command import environment_app
|
12
12
|
from ibm_watsonx_orchestrate.cli.commands.channels.channels_command import channel_app
|
13
13
|
from ibm_watsonx_orchestrate.cli.commands.knowledge_bases.knowledge_bases_command import knowledge_bases_app
|
14
|
+
from ibm_watsonx_orchestrate.cli.commands.toolkit.toolkit_command import toolkits_app
|
14
15
|
|
15
16
|
app = typer.Typer(
|
16
17
|
no_args_is_help=True,
|
@@ -18,15 +19,16 @@ app = typer.Typer(
|
|
18
19
|
)
|
19
20
|
app.add_typer(login_app)
|
20
21
|
app.add_typer(environment_app, name="env", help='Add, remove, or select the activate env other commands will interact with (either your local server or a production instance)')
|
21
|
-
app.add_typer(tools_app, name="tools", help='Interact with the tools in your active env')
|
22
22
|
app.add_typer(agents_app, name="agents", help='Interact with the agents in your active env')
|
23
|
+
app.add_typer(tools_app, name="tools", help='Interact with the tools in your active env')
|
24
|
+
app.add_typer(toolkits_app, name="toolkits", help="Interact with the toolkits in your active env")
|
25
|
+
app.add_typer(knowledge_bases_app, name="knowledge-bases", help="Upload knowledge your agents can search through to your active env")
|
23
26
|
app.add_typer(connections_app, name="connections", help='Interact with the agents in your active env')
|
24
|
-
app.add_typer(server_app, name="server", help='Manipulate your local
|
25
|
-
app.add_typer(chat_app, name="chat", help='Launch the chat ui for your local
|
27
|
+
app.add_typer(server_app, name="server", help='Manipulate your local Orchestrate Developer Edition server [requires entitlement]')
|
28
|
+
app.add_typer(chat_app, name="chat", help='Launch the chat ui for your local Developer Edition server [requires entitlement]')
|
26
29
|
app.add_typer(models_app, name="models", help='List the available large language models (llms) that can be used in your agent definitions')
|
30
|
+
app.add_typer(channel_app, name="channels", help="Configure channels where your agent can exist on (such as embedded webchat)")
|
27
31
|
app.add_typer(settings_app, name="settings", help='Configure the settings for your active env')
|
28
|
-
app.add_typer(channel_app, name="channels")
|
29
|
-
app.add_typer(knowledge_bases_app, name="knowledge-bases")
|
30
32
|
|
31
33
|
if __name__ == "__main__":
|
32
34
|
app()
|
@@ -0,0 +1,81 @@
|
|
1
|
+
from ibm_watsonx_orchestrate.client.base_api_client import BaseAPIClient, ClientAPIException
|
2
|
+
from typing_extensions import List
|
3
|
+
import os
|
4
|
+
import json
|
5
|
+
|
6
|
+
class ToolKitClient(BaseAPIClient):
|
7
|
+
# POST /toolkits/prepare/list-tools
|
8
|
+
def list_tools(self, zip_file_path: str, command: str, args: List[str]) -> List[str]:
|
9
|
+
"""
|
10
|
+
List the available tools inside the MCP server
|
11
|
+
"""
|
12
|
+
|
13
|
+
filename = os.path.basename(zip_file_path)
|
14
|
+
|
15
|
+
list_toolkit_obj = {
|
16
|
+
"source": "files",
|
17
|
+
"command": command,
|
18
|
+
"args": args,
|
19
|
+
}
|
20
|
+
|
21
|
+
with open(zip_file_path, "rb") as f:
|
22
|
+
files = {
|
23
|
+
"list_toolkit_obj": (None, json.dumps(list_toolkit_obj), "application/json"),
|
24
|
+
"file": (filename, f, "application/zip"),
|
25
|
+
}
|
26
|
+
|
27
|
+
response = self._post("/orchestrate/toolkits/prepare/list-tools", files=files)
|
28
|
+
|
29
|
+
return response.get("tools", [])
|
30
|
+
|
31
|
+
|
32
|
+
# POST /api/v1/orchestrate/toolkits
|
33
|
+
def create_toolkit(self, payload) -> dict:
|
34
|
+
"""
|
35
|
+
Creates new toolkit metadata
|
36
|
+
"""
|
37
|
+
try:
|
38
|
+
return self._post("/orchestrate/toolkits", data=payload)
|
39
|
+
except ClientAPIException as e:
|
40
|
+
if e.response.status_code == 400 and "already exists" in e.response.text:
|
41
|
+
raise ClientAPIException(
|
42
|
+
status_code=400,
|
43
|
+
message=f"There is already a Toolkit with the same name that exists for this tenant."
|
44
|
+
)
|
45
|
+
raise(e)
|
46
|
+
|
47
|
+
# POST /toolkits/{toolkit-id}/upload
|
48
|
+
def upload(self, toolkit_id: str, zip_file_path: str) -> dict:
|
49
|
+
"""
|
50
|
+
Upload zip file to the toolkit.
|
51
|
+
"""
|
52
|
+
filename = os.path.basename(zip_file_path)
|
53
|
+
with open(zip_file_path, "rb") as f:
|
54
|
+
files = {
|
55
|
+
"file": (filename, f, "application/zip", {"Expires": "0"})
|
56
|
+
}
|
57
|
+
return self._post(f"/orchestrate/toolkits/{toolkit_id}/upload", files=files)
|
58
|
+
|
59
|
+
# DELETE /toolkits/{toolkit-id}
|
60
|
+
def delete(self, toolkit_id: str) -> dict:
|
61
|
+
return self._delete(f"/orchestrate/toolkits/{toolkit_id}")
|
62
|
+
|
63
|
+
def get_draft_by_name(self, toolkit_name: str) -> List[dict]:
|
64
|
+
return self.get_drafts_by_names([toolkit_name])
|
65
|
+
|
66
|
+
def get_drafts_by_names(self, toolkit_names: List[str]) -> List[dict]:
|
67
|
+
formatted_toolkit_names = [f"names={x}" for x in toolkit_names]
|
68
|
+
return self._get(f"/orchestrate/toolkits?{'&'.join(formatted_toolkit_names)}")
|
69
|
+
|
70
|
+
def get_draft_by_id(self, toolkit_id: str) -> dict:
|
71
|
+
if toolkit_id is None:
|
72
|
+
return ""
|
73
|
+
else:
|
74
|
+
try:
|
75
|
+
toolkit = self._get(f"/orchestrate/toolkits/{toolkit_id}")
|
76
|
+
return toolkit
|
77
|
+
except ClientAPIException as e:
|
78
|
+
if e.response.status_code == 404 and "not found with the given name" in e.response.text:
|
79
|
+
return ""
|
80
|
+
raise(e)
|
81
|
+
|
@@ -13,7 +13,7 @@ services:
|
|
13
13
|
command: redis-server --loglevel warning
|
14
14
|
|
15
15
|
wxo-server-db:
|
16
|
-
image: us.icr.io
|
16
|
+
image: ${DB_REGISTRY:-us.icr.io/watson-orchestrate-private}/wxo-server-db:${DBTAG:-latest}
|
17
17
|
restart: unless-stopped
|
18
18
|
environment:
|
19
19
|
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
@@ -32,7 +32,7 @@ services:
|
|
32
32
|
command: -c shared_preload_libraries=pgsodium
|
33
33
|
|
34
34
|
wxo-server-connection-manager:
|
35
|
-
image: us.icr.io
|
35
|
+
image: ${CM_REGISTRY:-us.icr.io/watson-orchestrate-private}/wxo-connections:${CM_TAG:-latest}
|
36
36
|
platform: linux/amd64
|
37
37
|
restart: unless-stopped
|
38
38
|
environment:
|
@@ -44,12 +44,13 @@ services:
|
|
44
44
|
DB_PORT: ${DB_PORT:-5432}
|
45
45
|
DB_ENCRYPTION_KEY: abc
|
46
46
|
WXO_SERVER_URL: http://wxo-server:4321
|
47
|
-
MAX_POOL:
|
47
|
+
MAX_POOL: 60
|
48
|
+
DEPLOYMENT_MODE: laptop
|
48
49
|
ports:
|
49
50
|
- 3001:3001
|
50
51
|
|
51
52
|
ui:
|
52
|
-
image: us.icr.io
|
53
|
+
image: ${UI_REGISTRY:-us.icr.io/watson-orchestrate-private}/wxo-chat:${UITAG:-latest}
|
53
54
|
platform: linux/amd64
|
54
55
|
restart: unless-stopped
|
55
56
|
environment:
|
@@ -74,6 +75,7 @@ services:
|
|
74
75
|
MAX_FILE_UPLOAD_SIZE_BYTES_EXCEL: 1048576
|
75
76
|
VCAP_APP_HOST: localhost
|
76
77
|
DEPLOYMENT_PLATFORM: laptop
|
78
|
+
CONNECTION_MANAGER_URL: http://localhost:3001
|
77
79
|
DISMISS_NOTIFICATION_TIMEOUT: 10000
|
78
80
|
STANDALONE: "true"
|
79
81
|
STREAM_TIMEOUT: ${STREAM_TIMEOUT:-120000}
|
@@ -87,7 +89,7 @@ services:
|
|
87
89
|
- ui-data:/data
|
88
90
|
|
89
91
|
wxo-builder:
|
90
|
-
image: us.icr.io
|
92
|
+
image: ${BUILDER_REGISTRY:-us.icr.io/watson-orchestrate-private}/wxo-builder:${BUILDER_TAG:-latest}
|
91
93
|
platform: linux/amd64
|
92
94
|
restart: unless-stopped
|
93
95
|
environment:
|
@@ -199,7 +201,7 @@ services:
|
|
199
201
|
- wxo-server-redis
|
200
202
|
|
201
203
|
wxo-server:
|
202
|
-
image: us.icr.io
|
204
|
+
image: ${SERVER_REGISTRY:-us.icr.io/watson-orchestrate-private}/wxo-server-server:${SERVER_TAG:-latest}
|
203
205
|
platform: linux/amd64
|
204
206
|
restart: unless-stopped
|
205
207
|
ports:
|
@@ -294,7 +296,7 @@ services:
|
|
294
296
|
MILVUS_PASSWORD: Milvus
|
295
297
|
|
296
298
|
wxo-server-worker:
|
297
|
-
image: us.icr.io
|
299
|
+
image: ${WORKER_REGISTRY:-us.icr.io/watson-orchestrate-private}/wxo-server-conversation_controller:${WORKER_TAG:-latest}
|
298
300
|
platform: linux/amd64
|
299
301
|
restart: unless-stopped
|
300
302
|
depends_on:
|
@@ -372,7 +374,7 @@ services:
|
|
372
374
|
MILVUS_PASSWORD: Milvus
|
373
375
|
|
374
376
|
tools-runtime-manager:
|
375
|
-
image: us.icr.io
|
377
|
+
image: ${TRM_REGISTRY:-us.icr.io/watson-orchestrate-private}/tools-runtime-manager:${TRM_TAG:-latest}
|
376
378
|
platform: linux/amd64
|
377
379
|
restart: unless-stopped
|
378
380
|
ports:
|
@@ -409,7 +411,7 @@ services:
|
|
409
411
|
- "host.docker.internal:host-gateway"
|
410
412
|
|
411
413
|
tools-runtime:
|
412
|
-
image: us.icr.io
|
414
|
+
image: ${TR_REGISTRY:-us.icr.io/watson-orchestrate-private}/tools-runtime:${TR_TAG:-latest}
|
413
415
|
platform: linux/amd64
|
414
416
|
ports:
|
415
417
|
- "8000:8000"
|
@@ -527,7 +529,7 @@ services:
|
|
527
529
|
|
528
530
|
|
529
531
|
wxo-tempus-runtime:
|
530
|
-
image: us.icr.io/watson-orchestrate-private/wxo-tempus-runtime:${FLOW_RUNTIME_TAG:-latest}
|
532
|
+
image: ${FLOW_RUMTIME_REGISTRY:-us.icr.io/watson-orchestrate-private}/wxo-tempus-runtime:${FLOW_RUNTIME_TAG:-latest}
|
531
533
|
restart: unless-stopped
|
532
534
|
platform: linux/amd64
|
533
535
|
profiles: [with-tempus-runtime]
|
@@ -593,3 +595,4 @@ volumes:
|
|
593
595
|
networks:
|
594
596
|
default:
|
595
597
|
name: wxo-server
|
598
|
+
|
@@ -1,4 +1,3 @@
|
|
1
|
-
REGISTRY_URL=us.icr.io
|
2
1
|
#DOCKER_IAM_KEY=dummy #Must Define in env
|
3
2
|
#You can generate any JWT_SECRET with python -c 'import secrets; print(secrets.token_hex(32))'
|
4
3
|
JWT_SECRET=11759cbc89dbec64956715e10a854eb38f8b7a1775bdf68142786170f5e8b5b2
|
@@ -47,35 +46,39 @@ CELERY_RESULTS_TTL="3600"
|
|
47
46
|
EVENT_BROKER_TTL="-1"
|
48
47
|
|
49
48
|
# START -- IMAGE REGISTRIES AND TAGS
|
50
|
-
|
51
|
-
|
49
|
+
# THE VALUES FOR REGISTRY_URL AND *_REGISTRY ARE NOT SET HERE; THEY ARE EITHER PROVIDED BY THE USER OR DETERMINED AT RUNTIME BASED ON WO_DEVELOPER_EDITION_SOURCE.
|
50
|
+
REGISTRY_URL=
|
52
51
|
|
53
|
-
|
54
|
-
|
52
|
+
SERVER_TAG=03-05-2025
|
53
|
+
SERVER_REGISTRY=
|
55
54
|
|
56
|
-
|
55
|
+
WORKER_TAG=03-05-2025
|
56
|
+
WORKER_REGISTRY=
|
57
|
+
|
58
|
+
DB_REGISTRY=
|
57
59
|
# If you build multiarch set all three of these to the same, we have a pr against main
|
58
60
|
# to not have this separation, but we can merge it later
|
59
|
-
DBTAG=
|
60
|
-
AMDDBTAG=
|
61
|
-
ARM64DBTAG=
|
61
|
+
DBTAG=02-05-2025
|
62
|
+
AMDDBTAG=02-05-2025
|
63
|
+
ARM64DBTAG=02-05-2025
|
62
64
|
|
63
|
-
UI_REGISTRY=
|
64
|
-
UITAG=
|
65
|
+
UI_REGISTRY=
|
66
|
+
UITAG=01-05-2025
|
65
67
|
|
66
|
-
CM_REGISTRY=
|
68
|
+
CM_REGISTRY=
|
67
69
|
CM_TAG=30-04-2025
|
68
70
|
|
69
|
-
TRM_TAG=
|
70
|
-
TRM_REGISTRY=
|
71
|
+
TRM_TAG=02-05-2025
|
72
|
+
TRM_REGISTRY=
|
71
73
|
|
72
|
-
TR_TAG=
|
73
|
-
TR_REGISTRY=
|
74
|
+
TR_TAG=02-05-2025
|
75
|
+
TR_REGISTRY=
|
74
76
|
|
75
|
-
BUILDER_REGISTRY=
|
76
|
-
BUILDER_TAG=
|
77
|
+
BUILDER_REGISTRY=
|
78
|
+
BUILDER_TAG=02-05-2025
|
77
79
|
|
78
80
|
FLOW_RUNTIME_TAG=31-03-2025
|
81
|
+
FLOW_RUMTIME_REGISTRY=
|
79
82
|
|
80
83
|
# END -- IMAGE REGISTRIES AND TAGS
|
81
84
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
ibm_watsonx_orchestrate/__init__.py,sha256=
|
1
|
+
ibm_watsonx_orchestrate/__init__.py,sha256=QYUW_dfyamR2JbmoR89HSm5oP6_1q9B_-nA05eXp5BI,425
|
2
2
|
ibm_watsonx_orchestrate/agent_builder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
ibm_watsonx_orchestrate/agent_builder/agents/__init__.py,sha256=v4G0MGh11eOCkUJP_4AMOcFgzW14oE41G3iFp7G2vvw,376
|
4
4
|
ibm_watsonx_orchestrate/agent_builder/agents/agent.py,sha256=PcBg2dRi-IOzvl24u8fa3B0jLaM5hzgkpTS8k56L9Ag,919
|
@@ -14,13 +14,13 @@ ibm_watsonx_orchestrate/agent_builder/knowledge_bases/types.py,sha256=yvtf4zM0Ms
|
|
14
14
|
ibm_watsonx_orchestrate/agent_builder/tools/__init__.py,sha256=adkYX0wgB-RKFCUBw6LPJhNVelUjUdsxipGPk2ghLns,479
|
15
15
|
ibm_watsonx_orchestrate/agent_builder/tools/base_tool.py,sha256=unJBOJUY8DAq3T3YX5d1H5KehJUCjObAdpGLVoWIfzw,1156
|
16
16
|
ibm_watsonx_orchestrate/agent_builder/tools/openapi_tool.py,sha256=GD2yQkBSRHcnyq1LqA3crfo05rruqCj9vBS9xVDR2r0,14738
|
17
|
-
ibm_watsonx_orchestrate/agent_builder/tools/python_tool.py,sha256=
|
18
|
-
ibm_watsonx_orchestrate/agent_builder/tools/types.py,sha256=
|
17
|
+
ibm_watsonx_orchestrate/agent_builder/tools/python_tool.py,sha256=gh38bToYRnoqmsoR7pHCwqQTI6ENbxOPOV5aVSqECrg,8359
|
18
|
+
ibm_watsonx_orchestrate/agent_builder/tools/types.py,sha256=LcMEWTUYx_bAKK_gA8Uav-hSU5qsKl4_lJ7oWYgdfLc,5813
|
19
19
|
ibm_watsonx_orchestrate/agent_builder/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
20
|
ibm_watsonx_orchestrate/agent_builder/utils/pydantic_utils.py,sha256=QEanM6FpkmntvS02whdhWx1d4v6zT_1l9ipEbfTgHs8,7623
|
21
21
|
ibm_watsonx_orchestrate/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
-
ibm_watsonx_orchestrate/cli/config.py,sha256=
|
23
|
-
ibm_watsonx_orchestrate/cli/main.py,sha256=
|
22
|
+
ibm_watsonx_orchestrate/cli/config.py,sha256=C_iSP6WSb5SO6cVPTueQ9lEX16gYOLXD12cKXD6w_KQ,8168
|
23
|
+
ibm_watsonx_orchestrate/cli/main.py,sha256=Tey0gm3_z4JUbrKMSVFh_PEbCQqUGCohvnHRAU73KQA,2522
|
24
24
|
ibm_watsonx_orchestrate/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
25
25
|
ibm_watsonx_orchestrate/cli/commands/agents/agents_command.py,sha256=GVHM1wv28zGzOcc__3BXHt0Y5NXZuOr7PH8exwVqn-o,6640
|
26
26
|
ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py,sha256=mOoBwLltv5dpGdawoyXClUIsO3bIpZLOXrIXZ7Cney4,27920
|
@@ -39,15 +39,17 @@ ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_command.py,
|
|
39
39
|
ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_controller.py,sha256=mK9rMzslwIYDx8ebUs7QHVYAak6xm830_pKu3xH6F-s,8245
|
40
40
|
ibm_watsonx_orchestrate/cli/commands/login/login_command.py,sha256=xArMiojoozg7Exn6HTpbTcjDO2idZRA-y0WV-_Ic1Sk,651
|
41
41
|
ibm_watsonx_orchestrate/cli/commands/models/models_command.py,sha256=lxh0YpATogJRroHItwVuHmsZlHctVzWw_dEWkJlbwOI,4893
|
42
|
-
ibm_watsonx_orchestrate/cli/commands/server/server_command.py,sha256=
|
42
|
+
ibm_watsonx_orchestrate/cli/commands/server/server_command.py,sha256=fleb0JwH1PJ67M4ArL5l4vxoJAK1mtsIRFjHWSsKenI,28774
|
43
43
|
ibm_watsonx_orchestrate/cli/commands/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
44
44
|
ibm_watsonx_orchestrate/cli/commands/settings/settings_command.py,sha256=CzXRkd-97jXyS6LtaaNtMah-aZu0919dYl-mDwzGThc,344
|
45
45
|
ibm_watsonx_orchestrate/cli/commands/settings/observability/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
46
46
|
ibm_watsonx_orchestrate/cli/commands/settings/observability/observability_command.py,sha256=TAkpKwoqocsShSgEeR6LzHCzJx16VDQ6cYsbpljxeqI,372
|
47
47
|
ibm_watsonx_orchestrate/cli/commands/settings/observability/langfuse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
48
48
|
ibm_watsonx_orchestrate/cli/commands/settings/observability/langfuse/langfuse_command.py,sha256=Wa0L8E44EdxH9LdOvmnluLk_ApJVfTLauNOC1kV4W8k,6515
|
49
|
+
ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_command.py,sha256=hsVazoC25DUHtCFt3nmzkF5Eai59-tnNIJR51Emjk0E,2494
|
50
|
+
ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_controller.py,sha256=QRVyfXJAOHA4D5pgVcq7m4TnKwSSwwtyns3_rKc1Jcc,8499
|
49
51
|
ibm_watsonx_orchestrate/cli/commands/tools/tools_command.py,sha256=2GK5AKwEYXsOZaASG15J8yNIPakI0NYkSXBTkeuHj6s,3343
|
50
|
-
ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py,sha256=
|
52
|
+
ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py,sha256=i6JmF0sObMmIVWuWH2DVCirKLLW-NkFtj7n06dg3Yos,27688
|
51
53
|
ibm_watsonx_orchestrate/cli/commands/tools/types.py,sha256=_md0GEa_cTH17NO_moWDY_LNdFvyEFQ1UVB9_FltYiA,173
|
52
54
|
ibm_watsonx_orchestrate/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
53
55
|
ibm_watsonx_orchestrate/client/base_api_client.py,sha256=0ozLUudIrQH0RTdKaX0Y5c35FRNZPTemaAp71AsoMsQ,4410
|
@@ -68,9 +70,10 @@ ibm_watsonx_orchestrate/client/connections/__init__.py,sha256=u821r2ZiYXLYNTknxd
|
|
68
70
|
ibm_watsonx_orchestrate/client/connections/connections_client.py,sha256=aenYRfywM0lPlJWipFuy-Dnp2ljmpeP11oaWvPd69sA,7053
|
69
71
|
ibm_watsonx_orchestrate/client/connections/utils.py,sha256=XqgYoiehiqIZ-LnduIAiJ9DIIF7IR7QvkKTc9784Ii0,1326
|
70
72
|
ibm_watsonx_orchestrate/client/knowledge_bases/knowledge_base_client.py,sha256=U-pG_H0I8992f0V13Li_e1dksKp54MrYX3X9bvr-09w,2181
|
73
|
+
ibm_watsonx_orchestrate/client/toolkit/toolkit_client.py,sha256=1ZcOcjULV8xXqEVQpuDx_Nhh3dOFC2DA-RXMddl-wH0,2974
|
71
74
|
ibm_watsonx_orchestrate/client/tools/tool_client.py,sha256=pEKOBH488YbLVc71ucucX0rr8YoulvDCxejuyWd0K8s,1588
|
72
|
-
ibm_watsonx_orchestrate/docker/compose-lite.yml,sha256=
|
73
|
-
ibm_watsonx_orchestrate/docker/default.env,sha256=
|
75
|
+
ibm_watsonx_orchestrate/docker/compose-lite.yml,sha256=Br6wNrRNYVYeIpc4q_Usc-ENK0RzccE-67GSlYhwggw,24688
|
76
|
+
ibm_watsonx_orchestrate/docker/default.env,sha256=kuLLcXI24G4plLW8_7Af9K8VEVpt_zAhCOL1p-FVqS0,4609
|
74
77
|
ibm_watsonx_orchestrate/docker/start-up.sh,sha256=LTtwHp0AidVgjohis2LXGvZnkFQStOiUAxgGABOyeUI,1811
|
75
78
|
ibm_watsonx_orchestrate/docker/sdk/ibm_watsonx_orchestrate-0.6.0-py3-none-any.whl,sha256=Hi3-owh5OM0Jz2ihX9nLoojnr7Ky1TV-GelyqLcewLE,2047417
|
76
79
|
ibm_watsonx_orchestrate/docker/sdk/ibm_watsonx_orchestrate-0.6.0.tar.gz,sha256=e5T-q7XPAtiCyQljwZp6kk3Q_4Tg6y5sijHTkscmqqQ,2025466
|
@@ -82,8 +85,8 @@ ibm_watsonx_orchestrate/utils/utils.py,sha256=3JWk1J9A04yVZeetE3TQH82I53Sn20KvU_
|
|
82
85
|
ibm_watsonx_orchestrate/utils/logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
83
86
|
ibm_watsonx_orchestrate/utils/logging/logger.py,sha256=FzeGnidXAjC7yHrvIaj4KZPeaBBSCniZFlwgr5yV3oA,1037
|
84
87
|
ibm_watsonx_orchestrate/utils/logging/logging.yaml,sha256=9_TKfuFr1barnOKP0fZT5D6MhddiwsXVTFjtRbcOO5w,314
|
85
|
-
ibm_watsonx_orchestrate-1.0.
|
86
|
-
ibm_watsonx_orchestrate-1.0.
|
87
|
-
ibm_watsonx_orchestrate-1.0.
|
88
|
-
ibm_watsonx_orchestrate-1.0.
|
89
|
-
ibm_watsonx_orchestrate-1.0.
|
88
|
+
ibm_watsonx_orchestrate-1.2.0.dist-info/METADATA,sha256=ecvKQFIj26BZT-5M9fPjcfs371MR-NQIV89qrn6GNRQ,1251
|
89
|
+
ibm_watsonx_orchestrate-1.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
90
|
+
ibm_watsonx_orchestrate-1.2.0.dist-info/entry_points.txt,sha256=SfIT02-Jen5e99OcLhzbcM9Bdyf8SGVOCtnSplgZdQI,69
|
91
|
+
ibm_watsonx_orchestrate-1.2.0.dist-info/licenses/LICENSE,sha256=Shgxx7hTdCOkiVRmfGgp_1ISISrwQD7m2f0y8Hsapl4,1083
|
92
|
+
ibm_watsonx_orchestrate-1.2.0.dist-info/RECORD,,
|
File without changes
|
{ibm_watsonx_orchestrate-1.0.1.dist-info → ibm_watsonx_orchestrate-1.2.0.dist-info}/entry_points.txt
RENAMED
File without changes
|
{ibm_watsonx_orchestrate-1.0.1.dist-info → ibm_watsonx_orchestrate-1.2.0.dist-info}/licenses/LICENSE
RENAMED
File without changes
|