ibm-watsonx-orchestrate 1.7.0a0__py3-none-any.whl → 1.8.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.
Files changed (61) hide show
  1. ibm_watsonx_orchestrate/__init__.py +1 -1
  2. ibm_watsonx_orchestrate/agent_builder/agents/agent.py +3 -3
  3. ibm_watsonx_orchestrate/agent_builder/agents/assistant_agent.py +3 -2
  4. ibm_watsonx_orchestrate/agent_builder/agents/external_agent.py +3 -2
  5. ibm_watsonx_orchestrate/agent_builder/agents/types.py +38 -9
  6. ibm_watsonx_orchestrate/agent_builder/agents/webchat_customizations/prompts.py +1 -0
  7. ibm_watsonx_orchestrate/agent_builder/connections/connections.py +25 -10
  8. ibm_watsonx_orchestrate/agent_builder/connections/types.py +19 -11
  9. ibm_watsonx_orchestrate/agent_builder/knowledge_bases/knowledge_base_requests.py +1 -22
  10. ibm_watsonx_orchestrate/agent_builder/knowledge_bases/types.py +1 -17
  11. ibm_watsonx_orchestrate/agent_builder/tools/base_tool.py +2 -1
  12. ibm_watsonx_orchestrate/agent_builder/tools/openapi_tool.py +14 -13
  13. ibm_watsonx_orchestrate/agent_builder/tools/python_tool.py +136 -92
  14. ibm_watsonx_orchestrate/agent_builder/tools/types.py +10 -9
  15. ibm_watsonx_orchestrate/cli/commands/agents/agents_command.py +7 -7
  16. ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +35 -7
  17. ibm_watsonx_orchestrate/cli/commands/channels/types.py +15 -2
  18. ibm_watsonx_orchestrate/cli/commands/channels/webchat/channels_webchat_controller.py +35 -25
  19. ibm_watsonx_orchestrate/cli/commands/chat/chat_command.py +2 -0
  20. ibm_watsonx_orchestrate/cli/commands/connections/connections_command.py +14 -6
  21. ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +12 -12
  22. ibm_watsonx_orchestrate/cli/commands/copilot/copilot_command.py +65 -0
  23. ibm_watsonx_orchestrate/cli/commands/copilot/copilot_controller.py +368 -0
  24. ibm_watsonx_orchestrate/cli/commands/copilot/copilot_server_controller.py +170 -0
  25. ibm_watsonx_orchestrate/cli/commands/environment/environment_controller.py +6 -6
  26. ibm_watsonx_orchestrate/cli/commands/environment/types.py +3 -1
  27. ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_command.py +134 -36
  28. ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_controller.py +42 -11
  29. ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_command.py +0 -18
  30. ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_controller.py +36 -20
  31. ibm_watsonx_orchestrate/cli/commands/models/models_command.py +1 -1
  32. ibm_watsonx_orchestrate/cli/commands/models/models_controller.py +5 -8
  33. ibm_watsonx_orchestrate/cli/commands/server/server_command.py +59 -10
  34. ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_command.py +1 -1
  35. ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +93 -14
  36. ibm_watsonx_orchestrate/cli/config.py +3 -3
  37. ibm_watsonx_orchestrate/cli/init_helper.py +10 -1
  38. ibm_watsonx_orchestrate/cli/main.py +5 -0
  39. ibm_watsonx_orchestrate/client/base_api_client.py +12 -0
  40. ibm_watsonx_orchestrate/client/connections/connections_client.py +5 -30
  41. ibm_watsonx_orchestrate/client/copilot/cpe/copilot_cpe_client.py +67 -0
  42. ibm_watsonx_orchestrate/client/knowledge_bases/knowledge_base_client.py +1 -1
  43. ibm_watsonx_orchestrate/client/local_service_instance.py +3 -1
  44. ibm_watsonx_orchestrate/client/service_instance.py +33 -7
  45. ibm_watsonx_orchestrate/client/utils.py +49 -8
  46. ibm_watsonx_orchestrate/docker/compose-lite.yml +25 -6
  47. ibm_watsonx_orchestrate/docker/default.env +26 -15
  48. ibm_watsonx_orchestrate/flow_builder/flows/__init__.py +9 -4
  49. ibm_watsonx_orchestrate/flow_builder/flows/decorators.py +4 -2
  50. ibm_watsonx_orchestrate/flow_builder/flows/events.py +10 -9
  51. ibm_watsonx_orchestrate/flow_builder/flows/flow.py +131 -20
  52. ibm_watsonx_orchestrate/flow_builder/node.py +18 -1
  53. ibm_watsonx_orchestrate/flow_builder/types.py +271 -15
  54. ibm_watsonx_orchestrate/flow_builder/utils.py +121 -6
  55. ibm_watsonx_orchestrate/utils/exceptions.py +23 -0
  56. {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.8.0.dist-info}/METADATA +5 -5
  57. {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.8.0.dist-info}/RECORD +60 -56
  58. ibm_watsonx_orchestrate/flow_builder/resources/flow_status.openapi.yml +0 -66
  59. {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.8.0.dist-info}/WHEEL +0 -0
  60. {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.8.0.dist-info}/entry_points.txt +0 -0
  61. {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  from ibm_cloud_sdk_core.authenticators import MCSPAuthenticator
9
+ from ibm_cloud_sdk_core.authenticators import MCSPV2Authenticator
9
10
  from ibm_cloud_sdk_core.authenticators import IAMAuthenticator
10
11
  from ibm_cloud_sdk_core.authenticators import CloudPakForDataAuthenticator
11
12
 
@@ -51,24 +52,47 @@ class ServiceInstance(BaseServiceInstance):
51
52
  def _create_token(self) -> str:
52
53
  if not self._credentials.auth_type:
53
54
  if ".cloud.ibm.com" in self._credentials.url:
54
- logger.warning("Using IBM IAM Auth Type. If this is incorrect please use the '--type' flag to explicitly choose one of 'ibm_iam' or 'mcsp' or 'cpd")
55
+ logger.warning("Using IBM IAM Auth Type. If this is incorrect please use the '--type' flag to explicitly choose one of 'mcsp', 'mcsp_v1', 'mcsp_v2' or 'cpd' ")
55
56
  return self._authenticate(EnvironmentAuthType.IBM_CLOUD_IAM)
56
57
  elif is_cpd_env(self._credentials.url):
57
- logger.warning("Using CPD Auth Type. If this is incorrect please use the '--type' flag to explicitly choose one of 'ibm_iam' or 'mcsp' or 'cpd")
58
+ logger.warning("Using CPD Auth Type. If this is incorrect please use the '--type' flag to explicitly choose one of 'ibm_iam', 'mcsp', 'mcsp_v1' or 'mcsp_v2' ")
58
59
  return self._authenticate(EnvironmentAuthType.CPD)
59
60
  else:
60
- logger.warning("Using MCSP Auth Type. If this is incorrect please use the '--type' flag to explicitly choose one of 'ibm_iam' or 'mcsp' or 'cpd' ")
61
- return self._authenticate(EnvironmentAuthType.MCSP)
61
+ logger.warning("Using MCSP Auth Type. If this is incorrect please use the '--type' flag to explicitly choose one of 'ibm_iam', 'mcsp_v1', 'mcsp_v2' or 'cpd' ")
62
+ try:
63
+ return self._authenticate(EnvironmentAuthType.MCSP_V1)
64
+ except:
65
+ return self._authenticate(EnvironmentAuthType.MCSP_V2)
66
+ auth_type = self._credentials.auth_type.lower()
67
+ if auth_type == "mcsp":
68
+ try:
69
+ return self._authenticate(EnvironmentAuthType.MCSP_V1)
70
+ except:
71
+ return self._authenticate(EnvironmentAuthType.MCSP_V2)
72
+ elif auth_type == "mcsp_v1":
73
+ return self._authenticate(EnvironmentAuthType.MCSP_V1)
74
+ elif auth_type == "mcsp_v2":
75
+ return self._authenticate(EnvironmentAuthType.MCSP_V2)
62
76
  else:
63
- return self._authenticate(self._credentials.auth_type)
77
+ return self._authenticate(auth_type)
64
78
 
65
79
  def _authenticate(self, auth_type: str) -> str:
66
80
  """Handles authentication based on the auth_type."""
67
81
  try:
68
82
  match auth_type:
69
- case EnvironmentAuthType.MCSP:
83
+ case EnvironmentAuthType.MCSP | EnvironmentAuthType.MCSP_V1:
70
84
  url = self._credentials.iam_url if self._credentials.iam_url is not None else "https://iam.platform.saas.ibm.com"
71
85
  authenticator = MCSPAuthenticator(apikey=self._credentials.api_key, url=url)
86
+ case EnvironmentAuthType.MCSP_V2:
87
+ url = self._credentials.iam_url if self._credentials.iam_url is not None else "https://account-iam.platform.saas.ibm.com"
88
+ wxo_url = self._credentials.url
89
+ instance_id = wxo_url.split("instances/")[1]
90
+ authenticator = MCSPV2Authenticator(
91
+ apikey=self._credentials.api_key,
92
+ url=url,
93
+ scope_collection_type="services",
94
+ scope_id=instance_id
95
+ )
72
96
  case EnvironmentAuthType.IBM_CLOUD_IAM:
73
97
  authenticator = IAMAuthenticator(apikey=self._credentials.api_key, url=self._credentials.iam_url)
74
98
  case EnvironmentAuthType.CPD:
@@ -100,8 +124,10 @@ class ServiceInstance(BaseServiceInstance):
100
124
  raise ClientError(f"Unsupported authentication type: {auth_type}")
101
125
 
102
126
  return authenticator.token_manager.get_token()
127
+
103
128
  except Exception as e:
104
- raise ClientError(f"Error getting {auth_type.upper()} Token", e)
129
+ raise ClientError(f"Error getting {auth_type.upper()} Token", logg_messages=False)
130
+
105
131
 
106
132
 
107
133
  def _is_token_refresh_possible(self) -> bool:
@@ -16,22 +16,26 @@ from ibm_watsonx_orchestrate.cli.config import (
16
16
  from threading import Lock
17
17
  from ibm_watsonx_orchestrate.client.base_api_client import BaseAPIClient
18
18
  from ibm_watsonx_orchestrate.utils.utils import yaml_safe_load
19
+ from ibm_watsonx_orchestrate.cli.commands.channels.types import RuntimeEnvironmentType
19
20
  import logging
20
21
  from typing import TypeVar
21
22
  import os
22
23
  import jwt
23
24
  import time
25
+ import sys
24
26
 
25
27
  logger = logging.getLogger(__name__)
26
28
  LOCK = Lock()
27
29
  T = TypeVar("T", bound=BaseAPIClient)
28
30
 
31
+ def get_current_env_url() -> str:
32
+ cfg = Config()
33
+ active_env = cfg.read(CONTEXT_SECTION_HEADER, CONTEXT_ACTIVE_ENV_OPT)
34
+ return cfg.get(ENVIRONMENTS_SECTION_HEADER, active_env, ENV_WXO_URL_OPT)
29
35
 
30
36
  def is_local_dev(url: str | None = None) -> bool:
31
37
  if url is None:
32
- cfg = Config()
33
- active_env = cfg.read(CONTEXT_SECTION_HEADER, CONTEXT_ACTIVE_ENV_OPT)
34
- url = cfg.get(ENVIRONMENTS_SECTION_HEADER, active_env, ENV_WXO_URL_OPT)
38
+ url = get_current_env_url()
35
39
 
36
40
  if url.startswith("http://localhost"):
37
41
  return True
@@ -47,21 +51,58 @@ def is_local_dev(url: str | None = None) -> bool:
47
51
 
48
52
  return False
49
53
 
50
- def is_ibm_cloud():
51
- cfg = Config()
52
- active_env = cfg.read(CONTEXT_SECTION_HEADER, CONTEXT_ACTIVE_ENV_OPT)
53
- url = cfg.get(ENVIRONMENTS_SECTION_HEADER, active_env, ENV_WXO_URL_OPT)
54
+ def is_ga_platform(url: str | None = None) -> bool:
55
+ if url is None:
56
+ url = get_current_env_url()
57
+
58
+ if url.__contains__("orchestrate.ibm.com"):
59
+ return True
60
+ return False
61
+
62
+ def is_saas_env():
63
+ return is_ga_platform() or is_ibm_cloud_platform()
64
+
65
+ def is_ibm_cloud_platform(url:str | None = None) -> bool:
66
+ if url is None:
67
+ url = get_current_env_url()
54
68
 
55
69
  if url.__contains__("cloud.ibm.com"):
56
70
  return True
57
71
  return False
58
72
 
73
+ def is_cpd_env(url: str | None = None) -> bool:
74
+ if url is None:
75
+ url = get_current_env_url()
59
76
 
60
- def is_cpd_env(url: str) -> bool:
61
77
  if url.lower().startswith("https://cpd"):
62
78
  return True
63
79
  return False
64
80
 
81
+ def get_cpd_instance_id_from_url(url: str | None = None) -> str:
82
+ if url is None:
83
+ url = get_current_env_url()
84
+
85
+ if not is_cpd_env(url):
86
+ logger.error(f"The host {url} is not a CPD instance")
87
+ sys.exit(1)
88
+
89
+ url_fragments = url.split('/')
90
+ return url_fragments[-1] if url_fragments[-1] else url_fragments[-2]
91
+
92
+
93
+
94
+
95
+ def get_environment() -> str:
96
+ if is_local_dev():
97
+ return RuntimeEnvironmentType.LOCAL
98
+ if is_cpd_env():
99
+ return RuntimeEnvironmentType.CPD
100
+ if is_ibm_cloud_platform():
101
+ return RuntimeEnvironmentType.IBM_CLOUD
102
+ if is_ga_platform():
103
+ return RuntimeEnvironmentType.AWS
104
+ return None
105
+
65
106
  def check_token_validity(token: str) -> bool:
66
107
  try:
67
108
  token_claimset = jwt.decode(token, options={"verify_signature": False})
@@ -46,7 +46,7 @@ services:
46
46
  WXO_SERVER_URL: http://wxo-server:4321
47
47
  MAX_POOL: 60
48
48
  DEPLOYMENT_MODE: laptop
49
- SUFFIXLIST: '["global_05d7ba72", "ibm_184bdbd3"]'
49
+ SUFFIXLIST: ${CM_SUFFIXLIST:-[]}
50
50
  ports:
51
51
  - 3001:3001
52
52
 
@@ -120,7 +120,7 @@ services:
120
120
  TEMPUS_RUNTIME_ENDPOINT: http://wxo-tempus-runtime:9044
121
121
  CONNECTIONS_MANAGER_ENDPOINT: http://wxo-server-connection-manager:3001
122
122
  AGENT_OPS_API_KEY: ${AGENTOPS_API_KEY}
123
- AGENTS_OPS_RUNTIME_ENDPOINT: https://host.docker.internal:8765
123
+ AGENTS_OPS_RUNTIME_ENDPOINT: https://frontend-server:443
124
124
  IS_OBSERVABILITY_FEATURE_ENABLED: "true"
125
125
  ALLOW_INSECURE_TLS: "true"
126
126
  command: 'npm start'
@@ -751,8 +751,8 @@ services:
751
751
  SERVER_HTTP_PORT: "9044"
752
752
  SERVER_CONTEXT_PATH:
753
753
  SERVER_JWK_URL: https://wo-ibm-dev.verify.ibm.com/v1.0/endpoint/default/jwks
754
- SERVER_STANDALONE_TASK_CALLBACK_URL: http://localhost:9044/task/callback/{thread_id}/{requestId}
755
- SERVER_FLOW_CALLBACK_URL: http://localhost:9044/v1/flows/{flow_instance_id}/{task_instance_id}/resume/async
754
+ SERVER_STANDALONE_TASK_CALLBACK_URL: http://wxo-tempus-runtime:9044/task/callback/{thread_id}/{requestId}
755
+ SERVER_FLOW_CALLBACK_URL: http://wxo-tempus-runtime:9044/v1/flows/{flow_instance_id}/{task_instance_id}/resume/async
756
756
  JWT_SECRET: ${JWT_SECRET}
757
757
  SERVER_INTERNAL_PROTOCOL: http
758
758
  SERVER_INTERNAL_HOSTNAME: wxo-tempus-runtime
@@ -782,6 +782,7 @@ services:
782
782
  LOG_LEVEL: info
783
783
  DISABLE_FLOW_BINDING: true
784
784
  DOCPROC_ENABLED: ${DOCPROC_ENABLED:-false}
785
+ DOCPROC_BASE_URL: http://wxo-doc-processing-infra-standalone:9080
785
786
  WO_API_KEY: ${WO_API_KEY}
786
787
  WO_INSTANCE: ${WO_INSTANCE}
787
788
  AUTHORIZATION_URL: ${AUTHORIZATION_URL}
@@ -795,6 +796,23 @@ services:
795
796
  - 9044:9044
796
797
  depends_on:
797
798
  - wxo-server-db
799
+
800
+ cpe:
801
+ image: ${CPE_REGISTRY:-us.icr.io/watson-orchestrate-private}/wxo-prompt-optimizer:${CPE_TAG:-latest}
802
+ platform: linux/amd64
803
+ restart: unless-stopped
804
+ environment:
805
+ WATSONX_APIKEY: ${WATSONX_APIKEY}
806
+ WATSONX_SPACE_ID: ${WATSONX_SPACE_ID}
807
+ WO_API_KEY: ${WO_API_KEY}
808
+ WO_USERNAME: ${WO_USERNAME}
809
+ WO_PASSWORD: ${WO_PASSWORD}
810
+ WO_INSTANCE: ${WO_INSTANCE}
811
+ USE_SAAS_ML_TOOLS_RUNTIME: ${USE_SAAS_ML_TOOLS_RUNTIME}
812
+ WO_AUTH_TYPE: ${WO_AUTH_TYPE}
813
+ AUTHORIZATION_URL: ${AUTHORIZATION_URL}
814
+ ports:
815
+ - 8081:8080
798
816
 
799
817
  ########################
800
818
  # DOCPROC dependencies
@@ -863,7 +881,7 @@ services:
863
881
  condition: service_completed_successfully
864
882
 
865
883
  wdu-model-copy:
866
- image: ${WDU_REGISTRY:-us.icr.io/watson-orchestrate-private}/document-processing/wdu-runtime:${WDU_TAG:-2.4.0}
884
+ image: ${WDU_REGISTRY:-us.icr.io/watson-orchestrate-private}/document-processing/wdu-models:${WDU_TAG:-2.4.0}
867
885
  platform: linux/amd64
868
886
  user: root
869
887
  profiles:
@@ -898,10 +916,11 @@ services:
898
916
  ENRICHMENT_BATCH_SIZE: "1000"
899
917
  CIPHER_AES_REALM_KEY: "dGVzdHRlc3R0ZXN0dGVzdA=="
900
918
  SIDECAR_METERED_ENABLED: "false"
901
- DPI_DEBUG: true
919
+ DPI_DEBUG: "false"
902
920
  DPI_WO_WDU_SERVER_ENDPOINT: https://wxo-doc-processing-service:8080
903
921
  # DPI_RAG_SERVER_ENDPOINT: https://wxo-doc-processing-llm-service:8083
904
922
  DISABLE_TLS: true
923
+ STANDALONE_DPI: "true"
905
924
  depends_on:
906
925
  wxo-doc-processing-dpi-minio-init:
907
926
  condition: service_completed_successfully
@@ -53,16 +53,16 @@ EVENT_BROKER_TTL="-1"
53
53
  REGISTRY_URL=
54
54
 
55
55
 
56
- SERVER_TAG=26-06-2025
56
+ SERVER_TAG=10-07-2025-beb40a3a
57
57
  SERVER_REGISTRY=
58
58
 
59
- WORKER_TAG=26-06-2025
59
+ WORKER_TAG=10-07-2025-beb40a3a
60
60
  WORKER_REGISTRY=
61
61
 
62
- AI_GATEWAY_TAG=23-06-2025
62
+ AI_GATEWAY_TAG=01-07-2025
63
63
  AI_GATEWAY_REGISTRY=
64
64
 
65
- AGENT_GATEWAY_TAG=23-06-2025
65
+ AGENT_GATEWAY_TAG=07-07-2025
66
66
  AGENT_GATEWAY_REGISTRY=
67
67
 
68
68
  DB_REGISTRY=
@@ -73,41 +73,44 @@ AMDDBTAG=24-06-2025-v1
73
73
  ARM64DBTAG=24-06-2025-v1
74
74
 
75
75
  UI_REGISTRY=
76
- UITAG=26-06-2025
76
+ UITAG=21-07-2025
77
77
 
78
78
  CM_REGISTRY=
79
- CM_TAG=18-06-2025
79
+ CM_TAG=27-06-2025
80
80
 
81
- TRM_TAG=25-06-2025
81
+ TRM_TAG=08-07-2025
82
82
  TRM_REGISTRY=
83
83
 
84
- TR_TAG=25-06-2025
84
+ TR_TAG=08-07-2025
85
85
  TR_REGISTRY=
86
86
 
87
- BUILDER_TAG=26-06-2025-a
87
+ BUILDER_TAG=22-07-2025-v1
88
88
  BUILDER_REGISTRY=
89
89
 
90
- FLOW_RUNTIME_TAG=23-06-2025
90
+ FLOW_RUNTIME_TAG=15-07-2025
91
91
  FLOW_RUMTIME_REGISTRY=
92
92
 
93
93
 
94
- AGENT_ANALYTICS_TAG=24-06-2025
94
+ AGENT_ANALYTICS_TAG=02-07-2025-v1
95
95
  AGENT_ANALYTICS_REGISTRY=
96
96
 
97
- JAEGER_PROXY_TAG=24-06-2025
97
+ JAEGER_PROXY_TAG=01-07-2025
98
98
  JAEGER_PROXY_REGISTRY=
99
99
 
100
100
  SOCKET_HANDLER_TAG=29-05-2025
101
101
  SOCKET_HANDLER_REGISTRY=
102
102
 
103
+ CPE_TAG=17-07-2025
104
+ CPE_REGISTRY=
105
+
103
106
  # IBM Document Processing
104
- WDU_TAG=2.5.0-rc.2
107
+ WDU_TAG=2.5.0
105
108
  WDU_REGISTRY=
106
109
 
107
110
  DOCPROC_DPS_TAG=20250610-183301-248-865fbc1
108
111
  DOCPROC_LLMSERVICE_TAG=20250604-192056-107-e1d4d66
109
112
  DOCPROC_CACHE_TAG=20250610-214940-68-f3258f4
110
- DOCPROC_DPI_TAG=20250624-155521-230-48b7f28b
113
+ DOCPROC_DPI_TAG=20250702-000808-237-7b1e424d
111
114
  DOCPROC_REGISTRY=
112
115
 
113
116
  # END -- IMAGE REGISTRIES AND TAGS
@@ -161,6 +164,14 @@ DB_CONN_LIFE=
161
164
  DB_MAX_IDLE_CONN=
162
165
  DB_MAX_CONN=
163
166
  SERVER_HOST=
167
+ WO_API_KEY=
168
+ WO_PASSWORD=
169
+ WO_USERNAME=
170
+ WO_INSTANCE=
171
+ AUTHORIZATION_URL=
172
+ WO_AUTH_TYPE=
173
+ PYTHONPATH=
174
+ CM_SUFFIXLIST=
164
175
 
165
176
  # Use your machine's local IP address for external async tool communication.
166
177
  CALLBACK_HOST_URL=
@@ -172,4 +183,4 @@ RUNTIME_MANAGER_API_KEY=example
172
183
 
173
184
 
174
185
  # IBM Document Processing
175
- SERVICE_URL=https://wxo-doc-processing-cache:8080
186
+ SERVICE_URL=https://wxo-doc-processing-cache:8080
@@ -1,6 +1,8 @@
1
1
  from .constants import START, END, RESERVED
2
- from ..types import FlowContext, TaskData, TaskEventType
3
- from ..node import UserNode, AgentNode, StartNode, EndNode, PromptNode, ToolNode
2
+
3
+ from ..types import FlowContext, TaskData, TaskEventType, File, DecisionsCondition, DecisionsRule
4
+ from ..node import UserNode, AgentNode, StartNode, EndNode, PromptNode, ToolNode, DecisionsNode
5
+
4
6
  from .flow import Flow, CompiledFlow, FlowRun, FlowEvent, FlowEventType, FlowFactory, MatchPolicy, WaitPolicy, ForeachPolicy, Branch, Foreach, Loop
5
7
  from .decorators import flow
6
8
  from ..data_map import Assignment, DataMap
@@ -14,13 +16,16 @@ __all__ = [
14
16
  "FlowContext",
15
17
  "TaskData",
16
18
  "TaskEventType",
19
+ "File",
17
20
 
21
+ "DocProcNode",
18
22
  "UserNode",
19
23
  "AgentNode",
20
24
  "StartNode",
21
25
  "EndNode",
22
26
  "PromptNode",
23
27
  "ToolNode",
28
+ "DecisionsNode",
24
29
  "Assignment",
25
30
  "DataMap",
26
31
 
@@ -36,8 +41,8 @@ __all__ = [
36
41
  "Branch",
37
42
  "Foreach",
38
43
  "Loop",
44
+ "DecisionsCondition",
45
+ "DecisionsRule",
39
46
 
40
- "user",
41
- "flow_spec",
42
47
  "flow"
43
48
  ]
@@ -33,7 +33,8 @@ def flow(*args,
33
33
  description: str|None=None,
34
34
  input_schema: type[BaseModel] | None = None,
35
35
  output_schema: type[BaseModel] | None = None,
36
- initiators: Sequence[str] = ()):
36
+ initiators: Sequence[str] = (),
37
+ schedulable: bool = False):
37
38
  """Decorator to mark a function as a flow model builder."""
38
39
 
39
40
  def decorator(func: Callable):
@@ -58,7 +59,8 @@ def flow(*args,
58
59
  description = node_spec.description,
59
60
  input_schema = input_schema,
60
61
  output_schema = output_schema,
61
- initiators = initiators)
62
+ initiators = initiators,
63
+ schedulable = schedulable)
62
64
 
63
65
  # logger.info("Creating flow model: %s", a_model.spec.name)
64
66
 
@@ -5,9 +5,11 @@ from dotenv import load_dotenv
5
5
  import os
6
6
 
7
7
  from typing import (
8
- AsyncIterator, Union
8
+ AsyncIterator, TypeVar, Union
9
9
  )
10
10
 
11
+ from enum import Enum
12
+
11
13
  from ..types import (
12
14
  FlowEventType, TaskEventType, FlowEvent, FlowContext
13
15
  )
@@ -66,12 +68,11 @@ def deserialize_flow_event(byte_data: bytes) -> FlowEvent:
66
68
 
67
69
  return flow_event
68
70
 
71
+ def is_valid_enum_value(value: str, enum_type: type[Enum]) -> bool:
72
+ return value in (item.value for item in enum_type)
73
+
69
74
  def get_event_type(selected_event_type: str) -> Union[FlowEventType, TaskEventType]:
70
- """Selects the right event type from the corresponding enumerator"""
71
- eventKind = selected_event_type.upper()
72
- if eventKind in FlowEventType.__members__:
73
- return FlowEventType(selected_event_type)
74
- elif eventKind in TaskEventType.__members__:
75
- return TaskEventType(selected_event_type)
76
- else:
77
- raise ValueError(f"Invalid event type: {eventKind}")
75
+ for enum_type in [FlowEventType, TaskEventType]:
76
+ if is_valid_enum_value(selected_event_type, enum_type):
77
+ return enum_type(selected_event_type)
78
+ raise ValueError(f"Invalid event type: {selected_event_type}")
@@ -15,6 +15,7 @@ import logging
15
15
  import copy
16
16
  import uuid
17
17
  import pytz
18
+ import os
18
19
 
19
20
  from typing_extensions import Self
20
21
  from pydantic import BaseModel, Field, SerializeAsAny
@@ -25,11 +26,12 @@ from ibm_watsonx_orchestrate.client.tools.tempus_client import TempusClient
25
26
  from ibm_watsonx_orchestrate.client.utils import instantiate_client
26
27
  from ..types import (
27
28
  EndNodeSpec, Expression, ForeachPolicy, ForeachSpec, LoopSpec, BranchNodeSpec, MatchPolicy, PromptLLMParameters, PromptNodeSpec,
28
- StartNodeSpec, ToolSpec, JsonSchemaObject, ToolRequestBody, ToolResponseBody, UserFieldKind, UserFieldOption, UserFlowSpec, UserNodeSpec, WaitPolicy
29
+ StartNodeSpec, ToolSpec, JsonSchemaObject, ToolRequestBody, ToolResponseBody, UserFieldKind, UserFieldOption, UserFlowSpec, UserNodeSpec, WaitPolicy,
30
+ DocProcSpec, TextExtractionResponse, File, DecisionsNodeSpec, DecisionsRule
29
31
  )
30
32
  from .constants import CURRENT_USER, START, END, ANY_USER
31
33
  from ..node import (
32
- EndNode, Node, PromptNode, StartNode, UserNode, AgentNode, DataMap, ToolNode
34
+ EndNode, Node, PromptNode, StartNode, UserNode, AgentNode, DataMap, ToolNode, DocProcNode, DecisionsNode
33
35
  )
34
36
  from ..types import (
35
37
  AgentNodeSpec, extract_node_spec, FlowContext, FlowEventType, FlowEvent, FlowSpec,
@@ -114,7 +116,7 @@ class Flow(Node):
114
116
  # pydantic suppport nested comparison by default
115
117
 
116
118
  schema.title = title
117
-
119
+
118
120
  if schema == existing_schema:
119
121
  return existing_schema
120
122
  # we need to do a deep compare
@@ -354,6 +356,7 @@ class Flow(Node):
354
356
  name: str,
355
357
  agent: str,
356
358
  display_name: str|None=None,
359
+ title: str | None = None,
357
360
  message: str | None = "Follow the agent instructions.",
358
361
  description: str | None = None,
359
362
  input_schema: type[BaseModel]|None = None,
@@ -371,6 +374,7 @@ class Flow(Node):
371
374
  display_name=display_name,
372
375
  description=description,
373
376
  agent=agent,
377
+ title=title,
374
378
  message=message,
375
379
  guidelines=guidelines,
376
380
  input_schema=_get_tool_request_body(input_schema_obj),
@@ -428,6 +432,91 @@ class Flow(Node):
428
432
  # add the node to the list of node
429
433
  node = self._add_node(node)
430
434
  return cast(PromptNode, node)
435
+
436
+ def decisions(self,
437
+ name: str,
438
+ display_name: str|None=None,
439
+ rules: list[DecisionsRule] | None = None,
440
+ default_actions: dict[str, Any] = None,
441
+ locale: str | None = None,
442
+ description: str | None = None,
443
+ input_schema: type[BaseModel]|None = None,
444
+ output_schema: type[BaseModel]|None=None,
445
+ input_map: DataMap = None) -> PromptNode:
446
+
447
+ if name is None:
448
+ raise ValueError("name must be provided.")
449
+
450
+ if rules is None:
451
+ raise ValueError("rules must be specified.")
452
+
453
+ # create input spec
454
+ input_schema_obj = _get_json_schema_obj(parameter_name = "input", type_def = input_schema)
455
+ output_schema_obj = _get_json_schema_obj("output", output_schema)
456
+
457
+ # Create the tool spec
458
+ task_spec = DecisionsNodeSpec(
459
+ name=name,
460
+ display_name=display_name if display_name is not None else name,
461
+ description=description,
462
+ rules=rules,
463
+ default_actions=default_actions,
464
+ locale=locale,
465
+ input_schema=_get_tool_request_body(input_schema_obj),
466
+ output_schema=_get_tool_response_body(output_schema_obj),
467
+ output_schema_object = output_schema_obj
468
+ )
469
+
470
+ node = DecisionsNode(spec=task_spec)
471
+ # setup input map
472
+ if input_map:
473
+ node.input_map = self._get_data_map(input_map)
474
+
475
+ # add the node to the list of node
476
+ node = self._add_node(node)
477
+ return cast(DecisionsNode, node)
478
+
479
+ def docproc(self,
480
+ name: str,
481
+ task: str,
482
+ display_name: str|None=None,
483
+ description: str | None = None,
484
+ input_map: DataMap = None) -> DocProcNode:
485
+
486
+ if name is None :
487
+ raise ValueError("name must be provided.")
488
+
489
+ if task is None:
490
+ raise ValueError("task must be provided.")
491
+
492
+ output_schema_dict = {
493
+ "text_extraction" : TextExtractionResponse
494
+ }
495
+ # create input spec
496
+ input_schema_obj = _get_json_schema_obj(parameter_name = "input", type_def = File)
497
+ output_schema_obj = _get_json_schema_obj("output", output_schema_dict[task])
498
+ if "$defs" in output_schema_obj.model_extra:
499
+ output_schema_obj.model_extra.pop("$defs")
500
+ # Create the docproc spec
501
+ task_spec = DocProcSpec(
502
+ name=name,
503
+ display_name=display_name if display_name is not None else name,
504
+ description=description,
505
+ input_schema=_get_tool_request_body(input_schema_obj),
506
+ output_schema=_get_tool_response_body(output_schema_obj),
507
+ output_schema_object = output_schema_obj,
508
+ task=task
509
+ )
510
+
511
+ node = DocProcNode(spec=task_spec)
512
+ # setup input map
513
+ if input_map:
514
+ node.input_map = self._get_data_map(input_map)
515
+
516
+ # add the node to the list of node
517
+ node = self._add_node(node)
518
+ return cast(DocProcNode, node)
519
+
431
520
 
432
521
  def node_exists(self, node: Union[str, Node]):
433
522
 
@@ -921,7 +1010,8 @@ class FlowFactory(BaseModel):
921
1010
  description: str|None=None,
922
1011
  initiators: Sequence[str]|None=None,
923
1012
  input_schema: type[BaseModel]|None=None,
924
- output_schema: type[BaseModel]|None=None) -> Flow:
1013
+ output_schema: type[BaseModel]|None=None,
1014
+ schedulable: bool=False) -> Flow:
925
1015
  if isinstance(name, Callable):
926
1016
  flow_spec = getattr(name, "__flow_spec__", None)
927
1017
  if not flow_spec:
@@ -942,7 +1032,8 @@ class FlowFactory(BaseModel):
942
1032
  initiators=initiators,
943
1033
  input_schema=_get_tool_request_body(input_schema_obj),
944
1034
  output_schema=_get_tool_response_body(output_schema_obj),
945
- output_schema_object = output_schema_obj
1035
+ output_schema_object = output_schema_obj,
1036
+ schedulable=schedulable,
946
1037
  )
947
1038
 
948
1039
  return Flow(spec = flow_spec)
@@ -1228,10 +1319,12 @@ class UserFlow(Flow):
1228
1319
  kind: UserFieldKind = UserFieldKind.Text,
1229
1320
  display_name: str | None = None,
1230
1321
  description: str | None = None,
1231
- owners: list[str] = [],
1232
1322
  default: Any | None = None,
1233
- text: str = None,
1323
+ text: str = None, # The text used to ask question to the user, e.g. 'what is your name?'
1234
1324
  option: UserFieldOption | None = None,
1325
+ is_list: bool = False,
1326
+ min: Any | None = None,
1327
+ max: Any | None = None,
1235
1328
  input_map: DataMap = None,
1236
1329
  custom: dict[str, Any] = {}) -> UserNode:
1237
1330
  '''create a node in the flow'''
@@ -1246,20 +1339,42 @@ class UserFlow(Flow):
1246
1339
  schema_obj.properties = {}
1247
1340
  schema_obj.properties[name] = UserFieldKind.convert_kind_to_schema_property(kind, name, description, default, option, custom)
1248
1341
 
1249
- return self.user(name,
1250
- display_name=display_name,
1251
- description=description,
1252
- owners=owners,
1253
- text=text,
1254
- output_schema=schema_obj,
1255
- input_map=input_map)
1342
+ task_spec = UserNodeSpec(
1343
+ name=name,
1344
+ display_name=display_name,
1345
+ description=description,
1346
+ owners=[CURRENT_USER],
1347
+ input_schema=_get_tool_request_body(schema_obj),
1348
+ output_schema=_get_tool_response_body(schema_obj),
1349
+ text=text,
1350
+ output_schema_object = schema_obj
1351
+ )
1352
+
1353
+ node = UserNode(spec = task_spec)
1354
+ node.field(name = name,
1355
+ kind = kind,
1356
+ display_name = display_name,
1357
+ description = description,
1358
+ default = default,
1359
+ text = text,
1360
+ option = option,
1361
+ is_list = is_list,
1362
+ min = min,
1363
+ max = max,
1364
+ custom = custom)
1365
+
1366
+ # setup input map
1367
+ if input_map:
1368
+ node.input_map = self._get_data_map(input_map)
1369
+
1370
+ node = self._add_node(node)
1371
+ return cast(UserNode, node)
1256
1372
 
1257
1373
  def user(
1258
1374
  self,
1259
1375
  name: str | None = None,
1260
1376
  display_name: str | None = None,
1261
1377
  description: str | None = None,
1262
- owners: list[str] = [],
1263
1378
  text: str | None = None,
1264
1379
  output_schema: type[BaseModel] | JsonSchemaObject| None = None,
1265
1380
  input_map: DataMap = None,
@@ -1273,16 +1388,12 @@ class UserFlow(Flow):
1273
1388
  # input and output is always the same in an user node
1274
1389
  output_schema_obj = output_schema_obj
1275
1390
 
1276
- # identify owner
1277
- if not owners:
1278
- owners = [ANY_USER]
1279
-
1280
1391
  # Create the tool spec
1281
1392
  task_spec = UserNodeSpec(
1282
1393
  name=name,
1283
1394
  display_name=display_name,
1284
1395
  description=description,
1285
- owners=owners,
1396
+ owners=[CURRENT_USER],
1286
1397
  input_schema=_get_tool_request_body(output_schema_obj),
1287
1398
  output_schema=_get_tool_response_body(output_schema_obj),
1288
1399
  text=text,